2009-10-03 59 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=屬性的值,否則你會遍歷直到你得到一個太深的例外。