Reputation: 10413
I'm trying my hands on metaprogramming after a long pause. I found a few questions but could not get an input to solve my problem so I hope someone can enlighten me.
In a rails 5 app, I am trying to write a concern that provides a class method to set configuration options. With those options, I want to define instance methods.
module Base64Attachable
extend ActiveSupport::Concern
class_methods do
attr_reader :base64_attachable_property
private
def base64_attachable(property)
@base64_attachable_property = property
end
end
included do
# ?
end
end
The concern above is used inside a User
model:
class User < ApplicationRecord
include Base64Attachable
base64_attachable :image
end
In my understanding, the concern sets up the class method that is being called in the user model. However I do not seem to be able to get the base64_attachable_property
inside the included
block to define further methods based on the value of it. I thought I would find anything I need in self.class
inside the included
block, but that's not the case.
The aim in this case is to use define_method
to define setters, getters and other methods for image
in the user model.
What am I missing here?
Upvotes: 1
Views: 729
Reputation: 15838
The included
block is run at the moment the concern is included on the class, the base64_attachable :image
line is not run yet.
I'd suggest you follow what official gems does. Check ActiveStorage for example https://github.com/rails/rails/blob/530f7805ed5790af1d472a041bc74089dc183f47/activestorage/lib/active_storage/attached/model.rb#L35. It defines the methods that depends on that property right inside the class method (it uses class_eval, but I guess you can use define_method
too):
def has_one_attached(name, dependent: :purge_later)
generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{name}
@active_storage_attached_#{name} ||= ActiveStorage::Attached::One.new("#{name}", self)
end
def #{name}=(attachable)
attachment_changes["#{name}"] =
if attachable.nil?
ActiveStorage::Attached::Changes::DeleteOne.new("#{name}", self)
else
ActiveStorage::Attached::Changes::CreateOne.new("#{name}", self, attachable)
end
end
CODE
has_one :"#{name}_attachment", ......etc....
Upvotes: 3