What is the right way to override a setter method in Ruby on Rails?
===========================================================================
Update: July 19, 2017
Now the Rails documentation is also suggesting to use super
like this:
class Model < ActiveRecord::Base
def attribute_name=(value)
# custom actions
###
super(value)
end
end
===========================================================================
Original Answer
If you want to override the setter methods for columns of a table while accessing through models, this is the way to do it.
class Model < ActiveRecord::Base
attr_accessible :attribute_name
def attribute_name=(value)
# custom actions
###
write_attribute(:attribute_name, value)
# this is same as self[:attribute_name] = value
end
end
See Overriding default accessors in the Rails documentation.
So, your first method is the correct way to override column setters in Models of Ruby on Rails. These accessors are already provided by Rails to access the columns of the table as attributes of the model. This is what we call ActiveRecord ORM mapping.
Also keep in mind that the attr_accessible
at the top of the model has nothing to do with accessors. It has a completely different functionlity (see this question)
But in pure Ruby, if you have defined accessors for a class and want to override the setter, you have to make use of instance variable like this:
class Person
attr_accessor :name
end
class NewPerson < Person
def name=(value)
# do something
@name = value
end
end
This will be easier to understand once you know what attr_accessor
does. The code attr_accessor :name
is equivalent to these two methods (getter and setter)
def name # getter
@name
end
def name=(value) # setter
@name = value
end
Also your second method fails because it will cause an infinite loop as you are calling the same method attribute_name=
inside that method.
Override setter doesn't work with update_attributes
Your setter is passed the values as they are passed to update_attributes
. In particular when this is triggered by a form submission (and assuming you are using the regular rails form helpers) f
will actually be "0" or "1", so the comparison with true
will always be false.
The easiest thing would be to check the value of finished?
after the first call to write_attribute
, so that rails can convert the submitted value to true/false. It's also unrubyish to do == true
- this will break if the thing you are testing returns a truthy value rather than actually true (for example =~ on strings returns an integer when there is a match)
How to override a dynamically created setter method at runtime in Ruby?
Instead of using the default getter and setter:
singleton_class.send(:attr_accessor, name)
I suggest using a custom setter:
singleton_class.send(:attr_reader, name)
define_singleton_method("#{name}=") do |value|
if value.is_a?(Hash)
instance_variable_set("@#{name}", Config.new(value))
else
instance_variable_set("@#{name}", value)
end
end
public_send("#{name}=", value)
Ruby, how to overwrite the setter (=) method to allow 2 parameters?
As @eugen correctly says, you cannot pass two arguments to a setter like
self.my_vector = 1, 2
The nearest thing you can achieve is to unpack the argument using pattern matching:
def myvector=(arg)
arg => [x, y]
@my_vector = Vector2d.new(x, y)
end
foo.my_vector = [1, 2]
An alternative is to define a simple helper method v
so you can write
foo.my_vector = v 1, 2
Related Topics
Look Up All Descendants of a Class in Ruby
How to Replace Accented Latin Characters in Ruby
Ruby Multiline Block Without Do End
How to Update Ruby Version 2.0.0 to the Latest Version in MAC Osx Yosemite
Tzinfo::Datasourcenotfound Error Starting Rails V4.1.0 Server on Windows
Converting a Nested Hash into a Flat Hash
Get the Name of the Currently Executing Method
Trying to Learn/Understand Ruby Setter and Getter Methods
Oo Design in Rails: Where to Put Stuff
Ruby: What Does 'Require: False' in Gemfile Mean
Why Does String Interpolation Work in Ruby When There Are No Curly Braces
Pass Parameter by Reference' in Ruby
How to Skip the First Line of a CSV File and Make the Second Line the Header
How to Calculate Number of Chars Common to Two Strings