2010-10-05 112 views
110

我在模型觀察者中設置了after_save回調,只有當模型的已發佈的屬性從false更改爲true時,纔會發送通知。由於等方法改變了?保存模型前是唯一有用的,目前(和失敗)試圖這樣做如下:我的方式:確定Rails after_save回調中哪些屬性發生了變化?

def before_save(blog) 
    @og_published = blog.published? 
end 

def after_save(blog) 
    if @og_published == false and blog.published? == true 
    Notification.send(...) 
    end 
end 

沒有人有任何建議,以處理這種最好的方式,最好使用模型觀察者回調(以免污染我的控制器代碼)?

回答

151

在你after_update過濾器的模型,你可以使用訪問_changed?(至少在Rails 3中,不能確定爲Rails 2)。例如:

class SomeModel < ActiveRecord::Base 
    after_update :send_notification_after_change 

    def send_notification_after_change 
    Notification.send(...) if (self.published_changed? && self.published == true) 
    end 

end 

它只是工作。

+0

已經將它綁定在Rails 2.0.5中 - 完美工作 – stephenr 2010-10-05 08:27:58

+0

忘記我上面所說的 - 它在Rails 2.0.5中不起作用。所以一個有用的添加到Rails 3. – stephenr 2010-10-05 08:34:29

+2

正確的,很好的工具 - Rails 2.3.8包括在內。 – modulaaron 2010-10-05 08:36:40

-14

你只需要添加誰定義訪問你改變

class Post < AR::Base 
    attr_reader :what_changed 

    before_filter :what_changed? 

    def what_changed? 
    @what_changed = changes || [] 
    end 

    after_filter :action_on_changes 

    def action_on_changes 
    @what_changed.each do |change| 
     p change 
    end 
    end 
end 
+0

刪除回答這個問題... – Taysky 2016-12-13 19:58:34

5

「選定的」答案對我無效。我正在使用CouchRest :: Model(基於Active Model)的rails 3.1。 _changed?方法在after_update鉤子中僅在before_update鉤子中對於更改的屬性返回true。我使用能夠得到它的工作around_update鉤(新):

class SomeModel < ActiveRecord::Base 
    around_update :send_notification_after_change 

    def send_notification_after_change 
    should_send_it = self.published_changed? && self.published == true 

    yield 

    Notification.send(...) if should_send_it 
    end 

end 
+1

選定的答案也不適合我,但是這樣做。謝謝!我正在使用ActiveRecord 3.2.16。 – 2014-02-12 02:47:19

42

在情況下,你可以在before_save代替after_save做到這一點,你就可以使用這個:

self.changed 

它返回此記錄中所有更改列的數組。

你也可以使用:

self.changes 

它返回更改列前和結果陣列

+7

除了這些在'after_'回調中不起作用,這就是問題的實質。 @ jacek-głodek的答案在下面是正確的。 – Jazz 2014-12-22 21:26:40

+0

更新了答案,使之清楚這隻適用於'before_save' – mahemoff 2015-04-04 13:00:11

+1

哪個Rails版本是這樣的?在Rails 4中''self.changed'可以用在'after_save'回調函數中。 – sandre89 2016-11-24 04:55:44

0

我用這個來提取散列與新的屬性值後的哈希,對我來說,更新等車型

attributes_changed = self.changes.inject(Hash.new){|hash,attr| ((hash[attr[0].to_sym] = attr[1].last) || attr[1].last == false) && hash} 

這是有用的

在新值爲false時需要,其中賦值返回false並且不返回「散列」。

我想有一個更簡單的方法,我是新來的軌

113

對於那些想知道誰在更改保存後,你應該使用

model.previous_changes 

這就像model.change,但它的工作原理仍然在model.save之後,等等。 我發現這個information很有用,所以也許你也會。

In Rails 5.1+這已棄用。改爲使用saved_changes代替after_save回調。

+1

當您不想使用模型回調並需要在執行其他功能之前需要進行有效保存時,此功能完美無缺。 – 2015-01-20 03:39:25

+0

這是完美的!感謝您發佈此信息。 – jrhicks 2015-05-22 13:54:10

+6

謝謝,我愛你。 – mrodrigues 2015-10-07 21:17:50

14

爲了任何人看到這個以後,因爲它目前(8月2017)上衣谷歌:值得一提的是,這種行爲將在的Rails 5.2改變,並有廢棄警告像Rails 5.1的,因爲ActiveModel::Dirty改變了一下。

我該怎麼改變?

如果您使用attribute_changed?方法在after_* -callbacks,你會看到這樣的警告:

棄用警告:attribute_changed?內回調後的行爲將在未來版本中改變的Rails。新的返回值將反映在返回save之後調用方法的行爲(例如,它現在返回的結果的相反方向)。要保持當前行爲,請改爲使用saved_change_to_attribute?。 (在/PATH_TO/app/models/user.rb:15從some_callback調用)

因爲它提到,你可以用saved_change_to_attribute?更換功能輕鬆解決這個問題。例如,name_changed?變成saved_change_to_name?

同樣的,如果你使用的attribute_change拿到前後對照值,這改變以及和引發以下:

棄用警告:attribute_change行爲的內部回調後將會改變在下一個版本的Rails中。新的返回值將反映在返回save之後調用方法的行爲(例如,它現在返回的結果的相反方向)。要保持當前行爲,請改爲使用saved_change_to_attribute。 (在從/PATH_TO/app/models/user.rb:20稱爲some_callback)

再次,如它提到,該方法更名爲saved_change_to_attribute返回["old", "new"]。 或使用saved_changes,它會返回所有更改,並且這些更改可以作爲saved_changes['attribute']訪問。

0

,你可以添加一個條件到after_update像這樣:

class SomeModel < ActiveRecord::Base 
    after_update :send_notification, if: :published_changed? 

    ... 
end 

沒有必要到send_notification方法本身中添加一個條件。

相關問題