🧼
ActiveRecord::AttributeMethods::Dirty のメソッドをまとめてみる
こんにちは!
ラブグラフエンジニアのひろです!
データの更新を検知したいときに便利な ActiveRecord::AttributeMethods::Dirty
のメソッド群ですが、どのメソッドを使うか迷うことが多いので、まとめてみます!
便利なメソッドが多いですが、それぞれどのタイミングで使えるか分かりづらいのがつらいですね...
(だから Dirty???)
どんなメソッドがあるのか
前提となるデータ.rb
user = User.find_by(family_name: "みなせ", given_name: "ひろ")
=> #<User:0x00aaaaa
id: 123456,
family_name: "みなせ",
given_name: "ひろ",
...
attribute_before_last_save
直前に更新したカラムの、更新される前の値が取得できる
user.family_name = "水瀬"
=> nil # 更新前は取得できない
user.save!
user.family_name_before_last_save
=> "みなせ" # 更新される前の値
attribute_change_to_be_saved
更新される前の値と更新しようとしている値が取得できる
user.family_name = "水瀬"
user.family_name_change_to_be_saved
=> ["みなせ", "水瀬"] # 更新される前の値と更新しようとしている値
user.save!
user.family_name_change_to_be_saved
=> nil # 保存後は取得できない
attribute_in_database
その時点でDBに保存されている値を取得できる
user.family_name_in_database
=> "みなせ" # 現状の値
user.family_name = "水瀬"
user.family_name_in_database
=> "みなせ" # 更新前なので元の値
user.save!
user.family_name_in_database
=> "水瀬" # 更新後なので新しい値
attributes_in_database
更新しようとしているカラム名と元々の値が取得できる
user.family_name = "水瀬"
user.attributes_in_database
=> {"family_name"=>"みなせ"} # 更新しようとしているカラムと元々の値
user.save!
user.attributes_in_database
=> {} # 更新後は取得できない
changed_attribute_names_to_save
更新しようとしているカラム名が取得できる
user.family_name = "水瀬"
=> "水瀬"
user.changed_attribute_names_to_save
=> ["family_name"] # 更新しようとしているカラム名
user.save!
user.changed_attribute_names_to_save
=> [] # 更新後は取得できない
changes_to_save
更新しようとしているカラム名と、更新前後の値を取得できる
user.family_name = "水瀬"
user.changes_to_save
=> {"family_name"=>["みなせ", "水瀬"]} # 更新しようとしているカラム名と前後の値
user.changes_to_save
=> {} # 更新後は取得できない
has_changes_to_save?
更新される値があるかどうかを返す
user.family_name = "水瀬"
user.has_changes_to_save?
=> true # family_name が更新されうるので true
user.save!
user.has_changes_to_save?
=> false # 保存後は取得できない
reload
DBから取得し直して保存前の変更をクリア
user.family_name = "水瀬"
user.family_name
=> "水瀬"
user.reload
user.family_name
=> "みなせ" # 元々の値に戻る
saved_change_to_attribute
更新後に、特定のカラムの更新前後の値が取得できる
user.family_name = "水瀬"
user.saved_change_to_family_name
=> nil # 更新前は取得できない
user.save!
user.saved_change_to_family_name
=> ["みなせ", "水瀬"] # 更新前後の値
saved_change_to_attribute?
更新後に、特定のカラムが更新されたかどうかを返す
user.family_name = "水瀬"
user.saved_change_to_family_name?
=> false # 更新前なので false
user.save!
user.saved_change_to_family_name?
=> true # 更新されているので true
saved_changes
更新されたカラムの更新前後の値が取得できる
user.family_name = "水瀬"
user.saved_changes
=> {}
user.save!
user.saved_changes
=> {
"family_name"=>["みなせ", "水瀬"],
"updated_at"=>
[Mon, 13 Nov 2023 16:02:00.519392000 JST +09:00,
Mon, 13 Nov 2023 16:02:24.720393000 JST +09:00]
} # 更新されたカラムの更新前後の値
saved_changes?
更新されたカラムがあるかどうかを返す
user.family_name = "水瀬"
user.saved_changes?
=> false # 更新前なので false
user.save!
user.saved_changes?
=> true # 更新された後なので true
will_save_change_to_attribute?
特定のカラムが更新されるかどうかを返す
user.family_name = "水瀬"
user.will_save_change_to_family_name?
=> true # 更新前なので true
user.save!
user.will_save_change_to_family_name?
=> false # 更新後は false に
利用例
ユーザーネームの変更を検知し、変更履歴テーブルを作ることができますね。
## 更新前におこなうパターン
user.name = "水瀬"
if user.will_save_change_to_name?
UserNameHistory.create!(
before_name: user.name_in_database,
after_name: user.name
)
end
user.save!
## 更新後におこなうパターン
user.name = "水瀬"
user.save!
if user.saved_change_to_name?
UserNameHistory.create!(
before_name: user.name_before_last_save,
after_name: user.name
)
end
まとめ
今回は ActiveRecord::AttributeMethods::Dirty で利用できるメソッドを、簡単な使用例とともにまとめてみました!
ActiveRecord のコールバックとの組み合わせで少し複雑になってくるので、次回はその辺りを書いていこうと思います!
Discussion