概要
レコードの更新前後に、あるカラムにおける変更前の値を取得したい場面って結構ある気がするので、そんな時に使える方法を調べてみました。
changesメソッド
changesメソッドは、Active Recordモデルの属性の変更内容を返すメソッドです。このメソッドを呼び出すと、属性の変更前後の値がハッシュとして返されます。キーは属性名で、値は変更前後の値の配列です。
# ユーザーモデルの名前属性を変更する例
user = User.find(1)
puts user.name
# => "Alice"
user.name = "John"
puts user.changes
# => { "name" => ["Alice", "John"] }
attribute_in_databaseメソッド
attribute_in_databaseメソッドは、データベースに保存されている属性の値を返すメソッドです。このメソッドを呼び出すと、属性の現在のデータベース上の値が返されます。
# ユーザーモデルの年齢属性のデータベース上の値を取得する例
user = User.find(1)
puts user.age
# => 29
user.age = 30
puts user.attribute_in_database(:age)
# => 29
# {column_name}_in_databaseでも同様の結果が得られる
puts user.age_in_database
# => 29
上記の例では、Userモデルのage属性が変更されました。attribute_in_databaseメソッドを呼び出すことで、現在のデータベース上のage属性の値である29を取得することができます。
previous_changesメソッド
previous_changesメソッドは、dbに保存した後に直前の変更内容を返すメソッドです。
# ユーザーモデルのステータス属性を変更する例
user = User.find(1)
puts user.status
# => "active"
user.status = "inactive"
user.save
puts user.previous_changes
# => { "status" => ["active", "inactive"] }
上記の例では、Userモデルのstatus属性が変更されました。変更では"active"から"inactive"に変更されました。previous_changesメソッドを呼び出すことで、db更新後に直前の変更の内容を取得することができます。
attribute_before_last_saveメソッド
attribute_before_last_saveメソッドは、Active Recordモデルの属性が最後に保存される前の値を返すメソッドです。このメソッドを呼び出すと、属性の最後の保存前の値が取得できます。
以下にサンプルコードと使い方の説明を示します。
# ユーザーモデルの名前属性を変更して保存する例
user = User.find(1)
puts user.name
# => "John"
user.name = "Alice"
user.save
puts user.attribute_before_last_save(:name)
# => "John"
# {column_name}_before_last_saveでも同様の結果が得られる
puts user.name_before_last_save
# => "John"
上記の例では、Userモデルのname属性が変更されて保存されました。attribute_before_last_saveメソッドを使用して最後の保存前の値を取得しています。結果として、最後に保存される前のname属性の値である"John"が取得されます。
セッターのオーバーライド
セッターメソッドのオーバーライドでも、変更前の値を取得することができます。
class User < ApplicationRecord
def name=(*)
@name_before_changed = name
super
end
end
セッターをオーバーライドしてインスタンス変数に変更前の値を入れておくことで、変更前の値を保持しておくことも可能です。(あまりイケてる感じはしませんが、、)
gemを利用する
バージョン管理のgem(例:paper_trail)を使用すると、モデルの変更履歴を管理し、変更前の値を簡単に取得できます。具体的な使用方法はジェムによって異なりますので、各ジェムのドキュメントを参照してください。