1. ホーム
  2. ruby-on-rails

[解決済み] Railsで属性が変更されたときだけコールバックを実行する

2022-09-06 04:13:56

質問

私のアプリには、次のような関連付けがあります。

# Page 
belongs_to :status

を実行したときに、いつでもコールバックを実行できるようにしたい。 status_idpage が変更されました。

では、もし page.status_id が4から5になった場合、それをキャッチできるようにしたいのです。

どうすればいいのでしょうか?

どのように解決するのですか?

Rails 5.1以上

class Page < ActiveRecord::Base
  before_save :do_something, if: :will_save_change_to_status_id?

  private

  def do_something
    # ...
  end
end

ActiveRecord::Dirtyを変更したコミットはこちらです。 https://github.com/rails/rails/commit/16ae3db5a5c6a08383b974ae6c96faac5b4a3c81

この変更に関するブログ記事はこちらです。 https://www.fastruby.io/blog/rails/upgrades/active-record-5-1-api-changes

Rails 5.1+のActiveRecord::Dirtyの変更点について、自分用にまとめたものです。

ActiveRecord::Dirty (アクティブレコード::ダーティ)

https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Dirty.html

保存前 (オプション変更)

オブジェクトを変更した後、データベースに保存する前、または、オブジェクトの中にある before_save フィルタを使用することができます。

  • changes は、現在では changes_to_save
  • changed? は、現在 has_changes_to_save?
  • changed は、現在 changed_attribute_names_to_save
  • <attribute>_change は、現在 <attribute>_change_to_be_saved
  • <attribute>_changed? は、現在 will_save_change_to_<attribute>?
  • <attribute>_was は、現在 <attribute>_in_database

保存後 (ブレイキング・チェンジ)

オブジェクトを変更した後、データベースに保存した後、あるいは after_save フィルタを使用することができます。

  • saved_changes (代わりに previous_changes )
  • saved_changes?
  • saved_change_to_<attribute>
  • saved_change_to_<attribute>?
  • <attribute>_before_last_save

Rails <= 5.0

class Page < ActiveRecord::Base
  before_save :do_something, if: :status_id_changed?

  private

  def do_something
    # ...
  end
end

これは before_save コールバックがメソッド呼び出しの戻り値に基づいて条件付きで実行できることを利用しています。そのため status_id_changed? メソッドの由来は ActiveModel::Dirty を追加するだけで、特定の属性が変更されたかどうかを確認することができます。 _changed? を属性名に加えるだけで、特定の属性が変更されたかどうかを確認することができます。

の場合は do_something メソッドを呼び出すかどうかは、あなたのニーズ次第です。例えば before_save あるいは after_save または 定義されたActiveRecord::Callbacksは .