LoginSignup
337
211

More than 1 year has passed since last update.

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

Last updated at Posted at 2017-06-18

何が起きたか?

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

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

最後に

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

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

337
211
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
337
211