Reputation: 589
I don't know how to correctly phrase the title, I think the best way to explain this issue is just with code samples.
I want to define a meta method like this (in Rails 5):
class Post < ApplicationRecord
override_this_attribute_writer :some_attribute
end
The override_this_attribute_writer
follows a common pattern, it overrides the original writer by doing some filtering on top of it. I find this way of overriding very convenient and clear.
module MyCommonModule
extend ActiveSupport::Concern
module ClassMethods
def override_this_attribute_writer(attribute_name)
alias_method :"#{attribute_name}_old=", :"#{attribute_name}="
define_method :"#{attribute_name}=" do |a_value|
# Do my stuff
send(:"#{attribute_name}_old=", a_value)
end
end
end
When doing this, I was getting an exception at the call of alias_method
, because, apparently, the method I was trying to copy didn't exist (yet).
module MyCommonModule
extend ActiveSupport::Concern
module ClassMethods
def override_this_attribute_writer(attribute_name)
define_method :"#{attribute_name}=" do |a_value|
# Do my stuff
send(:write_attribute, attribute_name, a_value)
end
end
end
I was expecting this not to work: if, when running the meta method, ActiveRecord hasn't created the attribute writer yet, this means that it will do it later and override the method that I just defined.
But surprisingly it worked! So I put my hands inside ActiveRecord (5.1.5) to find out more.
I wanted to ensure that what I did was safe and it wasn't just working by accident: I looked into the definition of method writer, and put binding.pry
around the method.
This is the result of the experiment:
object.attribute=
object.attribute=
my own method is still called in place of the ActiveRecord oneSo, this is what I don't understand: if ActiveRecord seems to be overriding my method but it doesn't, what prevents it from doing it?
What in the end I need to know is whether the fix I have done is actually a good practice (and robust) or it's at risk and it might break if in the future we do upgrades.
If you think that my fix is dangerous, would you be able to suggest a different way to achieve the same goal?
Upvotes: 2
Views: 1123
Reputation: 8517
Calling super
is even more idiomatic:
module MyCommonModule
extend ActiveSupport::Concern
module ClassMethods
def override_this_attribute_writer(attribute_name)
define_method :"#{attribute_name}=" do |value|
# do some stuff
super value
end
end
end
end
Upvotes: 4