2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Ruby on Rails】データ変更前の値を取得する

Last updated at Posted at 2023-06-02

概要

レコードの更新前後に、あるカラムにおける変更前の値を取得したい場面って結構ある気がするので、そんな時に使える方法を調べてみました。

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)を使用すると、モデルの変更履歴を管理し、変更前の値を簡単に取得できます。具体的な使用方法はジェムによって異なりますので、各ジェムのドキュメントを参照してください。

2
1
0

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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?