何が起きたか?
Rails 5.1 へアップデートして大量に DEPRECATION WARNING や spec エラーが起きたので、調べてみると Rails 5.1 で ActiveRecord::AttributeMethods::Dirty の
- attribute_was
- attribute_change
- attribute_changed?
- changed?
- changed
辺りが非推奨になった。
参考: https://github.com/rails/rails/blob/ce93740a5e4437dfc1cf9b0b13da1bad06a2a598/activerecord/lib/active_record/attribute_methods/dirty.rb#L214-L237
何故それらが非推奨になったか
Rails の開発者が changed
系のバグ報告を良く受けるらしい。動作的に分かりづらい部分もあるが、 Rails が提供しているメソッドとしても attribute_change の様なメソッドで、メソッド名もアレなのと、どのタイミングでどんな値が入るのか正しく理解しないと利用することが出来ない。 (自分も結構このへんは悩んだ記憶がある。)
かなり大きな破壊的な変更にはなるが、移行パスはシンプルなようです。コードベースから改善し API をより直感的にすることによりそれらを改善しようとしたのがこの変更のようです。
自分も正しく理解できているか不安だし、結構想像で書いている部分もあるので、詳しくは下記 PR を。
https://github.com/rails/rails/pull/25337
移行
移行作業は理解さえ出来ればシンプルですが、単純な機械的な置換作業をすると大怪我をします。書き換える場所が save 前なのか、save 後なのかを意識して書き換える必要があります。正しくは after_create/after_update
より前か後かを意識すれば良いようです。
(https://github.com/rails/rails/blame/master/activerecord/lib/active_record/attribute_methods/dirty.rb#L19-L20)
変換表
表中の各 attribute
はカラム名に置き換えて hoge
というカラムで will_save_change_to_attribute?
を使いたければ will_save_change_to_hoge?
と読み替えてもらえると。
after_create/after_update
より前の場合
修正前 | 修正後 |
---|---|
attribute_changed? | will_save_change_to_attribute? |
attribute_change | attribute_change_to_be_saved |
attribute_was | attribute_in_database |
changes | changes_to_save |
changed? | has_changes_to_save? |
changed | changed_attribute_names_to_save |
changed_attributes | attributes_in_database |
after_create/after_update
より後の場合
修正前 | 修正後 |
---|---|
attribute_changed? | saved_change_to_attribute? |
attribute_change | saved_change_to_attribute |
attribute_was | attribute_before_last_save |
changes | saved_changes |
changed? | saved_changes? |
changed | saved_changes.keys |
changed_attributes | saved_changes.transform_values(&:first) |
嬉しいこと
after_create/after_update より後の場合
で書いているメソッドは callback が終わった後でも使えます。今まで save 後に record.changes
が取得できなかったのが、 record.saved_changes
をすれば前回の変更で何が変更されたかが取得できます。
と言っても、私の書いていたアプリではコレに該当する部分はありませんでしたが、、きっと嬉しい人はいるはず!
最後に
色んな所で似たような記事を見ましたが、正しくどのように対応すれば良いのかがイマイチまとまっていないものも多かったので、自分なりにまとめてみたつもりです。
ツッコミ・修正大歓迎です!