Rails after_saveコールバックでどの属性が変更されたかを決定しますか?
-
27-09-2019 - |
質問
モデルオブザーバーにafth_saveコールバックを設定して、モデルの場合にのみ通知を送信します 公開 属性はfalseからtrueに変更されました。次のような方法です かわった? モデルが保存される前にのみ便利です。現在(そして失敗して)そうしようとしている方法は次のとおりです。
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
これを処理するための最良の方法について、好ましくはモデルオブザーバーコールバックを使用している(コントローラーコードを汚染しないように)誰もが提案していますか?
解決
あなたの中で 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
それはただ機能します。
他のヒント
ちょうど行った変更を知りたい人のために after_save
折り返し電話:
Rails 5.1以上
model.saved_changes
レール<5.1
model.previous_changes
参照してください: http://api.rubyonrails.org/classes/activemodel/dirty.html#method-i-previous_changes
現在(2017年8月)がGoogleを上回っているので、これを後で見た人にとっては、この動作が変更されることは言及する価値があります。 Rails 5.2, 、およびRails 5.1の場合の非推奨警告があります。 ActiveModel ::ダーティ 少し変更しました。
何を変えますか?
使用している場合 attribute_changed?
の方法 after_*
- コールバック、次のような警告が表示されます。
非推奨警告:の動作
attribute_changed?
次のバージョンのRailsでは、After After Callbacksが変更されます。新しい返品値は、後にメソッドを呼び出す動作を反映しますsave
返された(例えば、それが今戻っているものの反対)。現在の動作を維持するには、使用しますsaved_change_to_attribute?
代わりは。 (some_callback at /path_to/app/models/user.rb:15から電話)
言及しているように、関数をに置き換えることでこれを簡単に修正できます saved_change_to_attribute?
. 。たとえば、 name_changed?
なります saved_change_to_name?
.
同様に、あなたが使用している場合 attribute_change
以前の値を取得するために、これも変更され、以下をスローします。
非推奨警告:の動作
attribute_change
次のバージョンのRailsでは、After After Callbacksが変更されます。新しい返品値は、後にメソッドを呼び出す動作を反映しますsave
返された(例えば、それが今戻っているものの反対)。現在の動作を維持するには、使用しますsaved_change_to_attribute
代わりは。 (some_callback at /path_to/app/models/user.rb:20から電話)
繰り返しますが、それが言及しているように、方法は名前を変更します saved_change_to_attribute
戻ります ["old", "new"]
。または使用します saved_changes
, 、すべての変更を返し、これらは次のようにアクセスできます saved_changes['attribute']
.
あなたがこれを行うことができる場合に備えて before_save
それ以外の after_save
, 、あなたはこれを使用することができます:
self.changed
このレコードのすべての変更された列の配列を返します。
使用することもできます。
self.changes
変更された列のハッシュをアレイとして結果として返します。
「選択された」答えは私にとってはうまくいきませんでした。 CouchRest :: Model(アクティブモデルに基づいて)でRails 3.1を使用しています。 _changed?
メソッドは、変更された属性の場合はtrueを返しません after_update
フック、でのみ before_update
針。 (新しい?)を使用して動作させることができました 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
に条件を追加できます after_update
そのようです:
class SomeModel < ActiveRecord::Base
after_update :send_notification, if: :published_changed?
...
end
内部に条件を追加する必要はありません send_notification
メソッド自体。
これを使用して、新しい属性値でハッシュを抽出します。これは、他のモデルを更新するのに役立ちます
attributes_changed = self.changes.inject(Hash.new){|hash,attr| ((hash[attr[0].to_sym] = attr[1].last) || attr[1].last == false) && hash}
attr[1].last == false
新しい価値があるときに必要です false
, 、割り当てがfalseを返し、「ハッシュ」が返されません。
私は簡単な方法があると思います、私はレールが初めてです
あなたが変えたものを定義するアクセサを追加するだけです
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