Device model has following attributes: name, version and full_name
Full name is name + version:
class Device < ActiveRecord::Base
def prepare
full_name = (!show_version || 开发者_开发百科version.nil?)? name : name + " " + version.to_s
end
end
When i do following:
d = Device.new :name => "iPhone", :version => "4"
d.prepare
d.full_name # get nil
I get nil for "full_name" attribute
When I'm using "self", it works:
class Device < ActiveRecord::Base
def prepare
self.full_name = (!show_version || version.nil?)? name : name + " " + version.to_s
end
end
Doing "prepare" i get "iPhone 4" for "full_name" attribute.
Some people here told me, that it's a good manner to avoid using "self" inside class methods. But this brings trouble.
The question is - why it does't works without using "self" ?
In these cases you have to use self, I don't think it's a trouble. If you are using self
then the interpreter will know that you refer to the object's attribute. If you don't use self
it means that it's just an local variable which is not stored anywhere after the method finishes.That's the normal behavior. You can also use self[:full_name]= ...
as a setter method, but in this case doesn't really matter.
Update
@AntonAL
Because the getter methods are recognized without the self.
.
When you try to use the name
attribute, the interpreter will look for a local variable within the current method. If doesn't finds then looks for an instance attribute. Example:
def your_method
self.name = 'iPhone'
puts name
#iPhone
name = 'iPod'
puts name
#iPod
puts self.name
#iPhone
end
And iPhone
will be stored in your object instance's name
attribute. And iPod
will be lost after the method finishes.
When you use setters, you need to use self
because otherwise Ruby will interpret it as a new local variable full_name
being defined.
For getters, we dont need to call self
because Ruby first search for a local variable full_name
and when it does not have a local variable full_name
, it will search for a method full_name
and will get the getter. If you have a local variable defined full_name
, it will return the value of local variable.
This is explained better in a previous question
This is expected because it's how ActiveRecord works by design. If you need to set arbitrary attributes, then you have to use a different kind of objects.
For example, Ruby provides a library called
OpenStruct
that allows you to create objects where you can assign arbitrary key and values. If you want get value from attribute without self, it's will give you instance of class OpenStruct with instance global variable attribute. But if you want set new attribute, it`s create new instance of class OpenStruct with new attributes. Without self you will have are old OpenStruct object which don't have attribute and will gave you error.
You may want to use such library and then convert the object into a corresponding ActiveRecord instance only when you need to save to the database.
Don't try to model ActiveRecord to behave as you just described because it was simply not designed to behave in that way
精彩评论