我正在使用Ruby on Rails 3.2.2,我想知道以下是否是一个“正确”/“正确”/“确定”的方式来覆盖我的类属性的setter方法。
attr_accessible :attribute_name
def attribute_name=(value)
... # Some custom operation.
self[:attribute_name] = value
end
上面的代码似乎按预期工作。但是,我想知道,通过使用上面的代码,将来我会遇到问题,或者至少是“我应该期待”/“可能发生在Ruby on Rails上”的问题。如果这不是覆盖setter方法的正确方法,那么正确的方法是什么?
注意:如果我使用代码
attr_accessible :attribute_name
def attribute_name=(value)
... # Some custom operation.
self.attribute_name = value
end
我收到以下错误:
SystemStackError (stack level too deep):
actionpack (3.2.2) lib/action_dispatch/middleware/reloader.rb:70
答案 0 :(得分:273)
<强> ============================================ =============================== 强> 更新:2017年7月19日
现在Rails documentation也建议像这样使用super
:
class Model < ActiveRecord::Base
def attribute_name=(value)
# custom actions
###
super(value)
end
end
<强> ============================================ =============================== 强>
原始答案
如果要在通过模型访问时覆盖表的列的setter方法,则可以使用此方法。
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
请参阅Rails文档中的Overriding default accessors。
因此,您的第一个方法是在Ruby on Rails的模型中覆盖列设置器的正确方法。这些访问器已由Rails提供,以作为模型的属性访问表的列。这就是我们所说的ActiveRecord ORM映射。
另请注意,模型顶部的 attr_accessible
与访问者无关。它具有完全不同的功能(参见this question)
但是在纯Ruby中,如果你为一个类定义了访问器并想要覆盖setter,你必须使用像这样的实例变量:
class Person
attr_accessor :name
end
class NewPerson < Person
def name=(value)
# do something
@name = value
end
end
一旦你知道attr_accessor
做什么,这将更容易理解。代码attr_accessor :name
等同于这两种方法(getter和setter)
def name # getter
@name
end
def name=(value) # setter
@name = value
end
此外,您的第二个方法失败,因为它会导致无限循环,因为您在该方法中调用相同的方法attribute_name=
。
答案 1 :(得分:42)
使用super
关键字:
def attribute_name=(value)
super(value.some_custom_encode)
end
相反,要覆盖读者:
def attribute_name
super.some_custom_decode
end
答案 2 :(得分:15)
在rails 4中
假设您的表格中有年龄属性
def age=(dob)
now = Time.now.utc.to_date
age = now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
super(age) #must add this otherwise you need to add this thing and place the value which you want to save.
end
注意: 对于rails 4中的新来者,您不需要在模型中指定 attr_accessible 。相反,您必须使用 permit 方法在控制器级别列出您的属性。
答案 3 :(得分:3)
我发现(至少对于ActiveRecord关系集合)以下模式有效:
has_many :specialties
def specialty_ids=(values)
super values.uniq.first(3)
end
(这会抓取传递的数组中的前3个非重复条目。)
答案 4 :(得分:0)
使用attr_writer
覆盖setter
attr_writer:attribute_name
def attribute_name=(value)
# manipulate value
# then send result to the default setter
super(result)
end