In custom validation methods, why are the attributes passed as local variables instead of being accessible as instance variables?
I was expecting to use @title instead of title in the custom validation below, but @title is nil in the code below. title contains the actual data.
attr_accessible :title
validate :do_check_title
def do_check_title
title =~ /^Alice in/ || errors.add(:title, "Not Alice in Wonderland")
end
Looking through the active_record/core.rb
def initialize(attributes = nil)
...
assign_attributes(attributes) if attributes
...
end
And then in active_record/attribute_assignment.rb
def _assign_attribute(k, v)
public_send("#{k}=", v)
So I guess, the attributes should be available as instance variables in the validation function.
Why are they nil?
It doesn't really matter if you access these from a validation or other instance methods. You can see what's happening from the console (pry):
u = User.first
show-method u.first_name=
This gives you something like this:
generated_attribute_methods.module_eval("def #{attr_name}=(new_value); write_attribute('#{attr_name}', new_value); end", __FILE__, __LINE__)
Now if you take a look at the write_attribute method, you can see that it deletes attribute cache etc. and then assign to attributes and it's just a hash.
u.attributes
So from now on, instead of the boring u.first_name = "foo", you can use this:
u.send :write_attribute, "first_name", "foo"
and it will do the same thing (3.2.10).
ActiveRecord stores the values in the attributes hash and not in instance variables. I generates accessor (getter/setter) methods on the fly while you access them.
Rails needs to support the livecycle of an entity, and wraps this code in the generated methods. This is needed, so that it can support ie. dirty? and changed? methods.
The next thing are associations, they are handled through proxies, so you need to call them with methods too.
Instance variables could be seen as volatile data. They are transparent to the persistance layer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With