179

モデルの公開された属性が false から true に変更された場合にのみ通知を送信するように、モデル オブザーバーで 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

できればモデルオブザーバーのコールバックを使用して、これを処理するための最良の方法について何か提案はありますか (私のコントローラーコードを汚染しないように)?

4

7 に答える 7

233

Rails 5.1+

使用saved_change_to_published?

class SomeModel < ActiveRecord::Base
  after_update :send_notification_after_change

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

end

または、必要に応じて、saved_change_to_attribute?(:published)

Rails 3–5.1

警告

このアプローチはRails5.1で機能します(ただし、5.1では非推奨であり、5.2では重大な変更があります)。このプルリクエストで変更について読むことができます。

モデルのafter_updateフィルターでは、アクセサーを使用できます。_changed?したがって、たとえば:

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

それはうまくいきます。

于 2010-10-05T08:09:06.977 に答える
204

コールバックで行われた変更を知りたい場合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

于 2013-12-18T12:08:35.480 に答える
78

現在 (2017 年 8 月) Google のトップにあるので、後でこれを見る人へ: ActiveModel::Dirtyが少し変更されたため、この動作はRails 5.2で変更され、Rails 5.1 の時点で非推奨の警告があることに注意してください。 .

何を変更すればよいですか?

attribute_changed?-callbacks でメソッドを使用している場合after_*、次のような警告が表示されます。

非推奨の警告: attribute_changed?Inside of after コールバックの動作は、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_changeInside of after コールバックの動作は、Rails の次のバージョンで変更されます。新しい戻り値は、返された後にメソッドを呼び出す動作を反映しますsave(たとえば、現在の戻り値の反対)。現在の動作を維持するには、saved_change_to_attribute代わりに を使用してください。(/PATH_TO/app/models/user.rb:20 の some_callback から呼び出されます)

繰り返しますが、言及されているように、メソッドは名前を変更saved_change_to_attributeします["old", "new"]。または use saved_changes、すべての変更を返します。これらには としてアクセスできますsaved_changes['attribute']

于 2017-08-03T19:45:24.010 に答える
49

before_saveの代わりに でこれを実行できる場合は、これafter_saveを使用できます。

self.changed

このレコードで変更されたすべての列の配列を返します。

次のものも使用できます。

self.changes

これは、変更された列と前後の結果のハッシュを配列として返します

于 2012-05-27T11:42:08.213 に答える
8

「選択された」答えは私にはうまくいきませんでした。Rails3.1をCouchRest::Model(アクティブモデルに基づく)で使用しています。メソッドは、フック内でのみ、フック_changed?内の変更された属性に対してtrueを返しません。(新しい?)フックを使用して動作させることができました:after_updatebefore_updatearound_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
于 2012-02-10T19:53:32.263 に答える
-20

変更内容を定義するアクセサーを追加するだけです

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
于 2010-10-05T08:08:29.110 に答える