开发者

Setting attribute from model without using self doesn't work

开发者 https://www.devze.com 2023-02-18 18:47 出处:网络
Device model has following attributes: name, version and full_name Full name is name + version: class Device < ActiveRecord::Base

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

0

精彩评论

暂无评论...
验证码 换一张
取 消