2009-10-03 62 views
17

我知道ActiveRecord ::脏和相关的方法,但我没有看到一种方法,我可以订阅属性更改事件。例如:更改ActiveRecord属性的回调?

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标准或插件?我觉得它一定在那里,我只是想念它。

回答

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 
+0

彼得,这是美丽的,将为我节省一大笔“write_attribute”,我遍布我的代码。谢谢! – BushyMark 2009-10-04 00:32:34

+0

似乎这只适用于Rails 2。 – lulalala 2013-10-23 10:41:19

+0

通过谷歌来到这个没有检查日期。这个更近期的演练做了我所需要的:[如何跟踪'after_callbacks'中模型的变化](http://ruby-journal.com/how-to-track-changes-with-after-callbacks-in- rails-3-or-newer /) – Jay 2014-07-03 19:10:03

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 

现在只是发明了这一点,但它应该工作。

+0

谢谢你让我走上正确的道路。 – Mario 2009-10-04 13:46:10

3

你总是可以访问私有方法changed_attributes,并检查按键也使用before_save,并用它做什么,你会的。

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

我相信他希望一个方法在内存中的属性被改变之前立即被调用,在调用save之前,即'my_object.some_attr =“foo”'会产生一个回调。 – MikeJ 2013-07-05 14:32:16

+0

'after_update'已被弃用,因为rails 2.3(http://apidock.com/rails/ActiveRecord/Callbacks/after_update) – schmijos 2015-02-09 10:20:18

2

,我发现最简单的方法:

after_save :my_method, :if => Proc.new{ self.my_attribute_changed? } 

def my_method 
    ... do stuff... 
end 
+1

after_save:my_method,:if =>:my_attribute_changed? – 2013-12-18 14:19:33

+0

不错!它甚至更好:) – pesta 2013-12-19 19:16:08

8

对于轨道4

def attribute=(value) 
    super(value) 
    your_callback(self.attribute) 
end 

如果要覆盖你应该使用write_attribute(:attribute, your_callback(self.attribute))而不是attribute=属性的值,否则你会遍历直到你得到一个太深的例外。