Edited at

Rails 5.1 で attribute_was, attribute_change, attribute_changed?, changed?, changed 等が DEPRECATION WARNING

More than 1 year has passed since last update.


何が起きたか?

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/master/activerecord%2Flib%2Factive_record%2Fattribute_methods%2Fdirty.rb#L213-L236


何故それらが非推奨になったか

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)


変換表


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 をすれば前回の変更で何が変更されたかが取得できます。

と言っても、私の書いていたアプリではコレに該当する部分はありませんでしたが、、きっと嬉しい人はいるはず!


最後に

色んな所で似たような記事を見ましたが、正しくどのように対応すれば良いのかがイマイチまとまっていないものも多かったので、自分なりにまとめてみたつもりです。

ツッコミ・修正大歓迎です!