Differences between *, self.* and @* when referencing associations/attributes in Ruby/Rails Models/Controllers
self.x
/self.x=y
are always method calls.
(self.x
is just sugar for self.__send__(:x)
and self.x = y
is really just sugar for self.__send__(:x=, y)
)
@x
, on the other hand, only refers to an instance variable.
Using @x
will not work with AR associations as AR only defines x/x=
(which are methods) for its magical operation. (AR essentially just "captures" intent access through these methods and routes through its own internal data structures which are unrelated to any similar-named instance variables.)
attr_accessor
allows "accessing both ways" because and only because it uses the same-named instance variable as it's backing (it has to store the value somewhere). Consider that attr_accessor :x
is equivalent to:
def x; @x; end
def x= (y); @x = y; end
Happy coding.
Do I need to use attr_accessor?
Using attr_accessor
has nothing to do with Active Record. I discuss how it works in this post, that is also related to AR.
Now, what AR does do, is it automatically creates is own "accessor" methods (e.g. x/x=
) based on the database model. These automatically created methods are really just stubs that it uses to proxy into the internal AR workings.
The point is, attr_accessor
(automatically) wraps simple instance variable access, while AR (automatically) created methods wrap AR magic. The two operations are mutually exclusive. Because attr_accessor
does not "link to" the AR magic, all it can be used for creating transient fields which are not persisted: AR does not know of or care about instance variables.
The "danger" comes from perhaps complicating the model objects with transient information -- if it is transient, why should it be part of a model object? This is the argument the most up-voted answer in the linked question makes.
Happy coding.
However, I do no know what would happen if using attr_accessor
for the same field as that which happens to be in the AR model... confusion at the least.
Rails 5 add non persistent ActiveRecord attributes dynamically
While I am sure there is a more ActiveModel
(RoR Guides, API - but it might not be ActiveModel
but a similar module) way of doing this, with plain Ruby you would do it like this:
r_v.send("count_#{r.b_id}_erg_bst=", 0)
Basically, you "call" the method count_..._erg...=
(a method assigning the local variable, defined by attr_accessor
) with the argument 0
.
For r.bid == 'my'
it would be the same as calling r_v.count_my_erg_bst= 0
.
Note that this will only work if something like attr_accessor :count_my_erg_bst
is part of your class definition.
Otherwise, you can do it more meta-programmingish whith something like rv.instance_eval { @count_my_erg_bst = 0 }
or, because you need string interpolationrv.instance_eval " @count_#{r.bid}_erg_bst = 0 "
Note the security implications! If r.bid
is provided by the user, it could be something like "a = 1; system("rm -rf /");"
or other harmful code!
Instance variables vs. lazy loading method
You wrap an instance variable in a method when you do not want to get exactly the instance variable, but a little more than that. For example, if you want to memoize, then instead of calling
@foo
rather you need to put it in a method and call it
def foo; @foo ||= ... end
foo ...
Or if you want to return a different value than the variable's when the variable takes a certain value, then you need to put a condition in it
def foo
if @foo == ... then ... else @foo end
end
foo ...
Rails 3 - Update every attribute that is present in a model instance (encode every value)
class Book < ActiveRecord::Base
before_save :recode_attribs
private
def recode_attribs
attributes.each do |name, value|
next unless value.respond_to?(:encode)
attributes[name] = value.encode('ISO-8859-1')
end
end
end
Related Topics
Converting an Empty String into Nil in Ruby
How to Export a Ruby Array from My Heroku Console into CSV
How to Use an Actionview::Helper in a Ruby Script, Outside of Rails
Rbenv Build Failed on Ubuntu 14.04
Ruby Singleton Methods for Class and Objects
How to Create Database from Schema.Rb Without Initializing Rails
How to Override Static Class Method Using Module in Ruby
Key Issue with Installing Rvm (Ruby Version Manager)
Spinach VS Cucumber for Bdd in Rails
Ruby: Put Request with JSON Body
Ruby Merging Two Arrays into One
Rubymine - No Ruby Interpreter Configured for the Project