我知道ActiveRecord :: Dirty及相关方法,但我没有看到可以订阅属性更改事件的方法。类似的东西:
class Person < ActiveRecord::Base
def attribute_changed(attribute_name, old_value, new_value)
end
#or
attribute_changed do |attribute_name, old_value, new_value|
end
end
是否有Rails标准或插件?我觉得它必定存在于某处,而我却错过了它。
答案 0 :(得分:18)
cwninja的回答应该可以解决问题,但还有更多的内容。
首先,使用write_attribute方法完成基本属性处理,因此您应该使用它。
Rails也有一个内置的回调结构,虽然它不允许传递有点烦人的参数,但它可能很好用。
使用自定义回调你可以这样做:
class Person < ActiveRecord::Base
def write_attribute(attr_name, value)
attribute_changed(attr_name, read_attribute(attr_name), value)
super
end
private
def attribute_changed(attr, old_val, new_val)
logger.info "Attribute Changed: #{attr} from #{old_val} to #{new_val}"
end
end
如果您想尝试使用Rails回调(如果您可能有多个回调和/或子类,则特别有用),您可以执行以下操作:
class Person < ActiveRecord::Base
define_callbacks :attribute_changed
attribute_changed :notify_of_attribute_change
def write_attribute(attr_name, value)
returning(super) do
@last_changed_attr = attr_name
run_callbacks(:attribute_changed)
end
end
private
def notify_of_attribute_change
attr = @last_changed_attr
old_val, new_val = send("#{attr}_change")
logger.info "Attribute Changed: #{attr} from #{old_val} to #{new_val}"
end
end
答案 1 :(得分:14)
对于Rails 3:
class MyModel < ActiveRecord::Base
after_update :my_listener, :if => :my_attribute_changed?
def my_listener
puts "Attribute 'my_attribute' has changed"
end
end
评论:https://stackoverflow.com/a/1709956/316700
我找不到关于此的官方文档。
答案 2 :(得分:8)
对于Rails 4
def attribute=(value)
super(value)
your_callback(self.attribute)
end
如果你想覆盖属性的值,你应该使用write_attribute(:attribute, your_callback(self.attribute))
而不是attribute=
,否则你将循环遍历它,直到你得到一个堆栈太深的异常。
答案 3 :(得分:5)
尝试:
def attribute_changed(attribute_name, old_value, new_value)
end
def attribute=(attribute_name, value)
returning(super) do
attribute_changed(attribute_name, attribute_was(attribute_name), attribute(attribute_name))
end
end
现在就发明了这个,但它应该有效。
答案 4 :(得分:3)
您始终可以访问私有方法changed_attributes
并使用before_save
检查其中的密钥并按照您的意愿执行操作。
答案 5 :(得分:2)
我发现最简单的方法:
after_save :my_method, :if => Proc.new{ self.my_attribute_changed? }
def my_method
... do stuff...
end