LoginSignup
86
61

More than 5 years have passed since last update.

RailsのActiveRecordでカラムの変更前後の情報を取得

Last updated at Posted at 2016-03-03

はじめに

ActiveRecordで{attr_name}_wasのメソッドをコールバック時に利用してみたので、せっかくだったらと思い以下のメソッド全部の実行結果をまとめてみる。

  • changed?
  • changed
  • changes
  • {attr_name}_changed?
  • {attr_name}_was
  • {attr_name}_change

※この子だけ使う機会がよく分からないので割愛します!

  • {attr_name}_will_change!

メソッド詳しく知りたい方は以下のリンクからソースコードどうぞ
rails/activemodel/lib/active_model/dirty.rb

目的

以下のコールバック時での各メソッドの実行結果を確認する

  • before_save
  • after_save
  • after_commit

試した内容

色々試すように適当なtestモデル作成

app/models/test.rb
# == Schema Information
#
# Table name: tests
#
#  id                     :integer          not null, primary key
#  score                  :integer          not null
#  grade                  :text(65535)      not null
#  created_at             :datetime         not null
#  updated_at             :datetime         not null
#

class Test < ActiveRecord::Base
  before_save  TestCallbacks.new
  after_save   TestCallbacks.new
  after_commit TestCallbacks.new
end

コールバックはあえて分けて用意(理由は特にない
全てのタイミングでbinding.pryを差し込んでみる

app/models/test_callbacks.rb
class TestCallbacks
  def before_save(test)
    binding.pry
  end

  def after_save(test)
    binding.pry
  end

  def after_commit(test)
    binding.pry
  end
end

以下のようなテストデータ用意してgradeカラムを更新

pry(main)> test = Test.first
+----+-------+-------+---------------------------+---------------------------+
| id | score | grade | created_at                | updated_at                |
+----+-------+-------+---------------------------+---------------------------+
| 1  | 80    | C     | 2016-03-03 18:05:55 +0900 | 2016-03-03 18:05:55 +0900 |
+----+-------+-------+---------------------------+---------------------------+
pry(main)> test.update(grade: 'B')

before_saveのタイミングでの結果

[7] pry(#<TestCallbacks>)> test.grade
"B"
[8] pry(#<TestCallbacks>)> test.changed?
true
[9] pry(#<TestCallbacks>)> test.changed
[
    [0] "grade"
]
[10] pry(#<TestCallbacks>)> test.changes
{
    "grade" => [
        [0] "C",
        [1] "B"
    ]
}
[11] pry(#<TestCallbacks>)> test.grade_changed?
true
[12] pry(#<TestCallbacks>)> test.score_changed?
false
[13] pry(#<TestCallbacks>)> test.grade_was
"C"
[14] pry(#<TestCallbacks>)> test.grade_change
[
    [0] "C",
    [1] "B"
]

after_saveのタイミングでの結果

※updated_atカラムが更新されようとしている以外は変わらない

pry(#<TestCallbacks>)> test.grade
"B"
pry(#<TestCallbacks>)> test.changed?
true
pry(#<TestCallbacks>)> test.changed
[
    [0] "grade",
    [1] "updated_at"
]
pry(#<TestCallbacks>)> test.changes
{
         "grade" => [
        [0] "C",
        [1] "B"
    ],
    "updated_at" => [
        [0] Thu, 03 Mar 2016 18:05:55 JST +09:00,
        [1] Thu, 03 Mar 2016 19:03:51 JST +09:00
    ]
}
pry(#<TestCallbacks>)> test.grade_changed?
true
pry(#<TestCallbacks>)> test.score_changed?
false
pry(#<TestCallbacks>)> test.grade_was
"C"
pry(#<TestCallbacks>)> test.grade_change
[
    [0] "C",
    [1] "B"
]

after_commitのタイミングでの結果

pry(#<TestCallbacks>)> test.grade
"B"
pry(#<TestCallbacks>)> test.changed?
false
pry(#<TestCallbacks>)> test.changed
[]
pry(#<TestCallbacks>)> test.changes
{}
pry(#<TestCallbacks>)> test.grade_changed?
false
pry(#<TestCallbacks>)> test.grade_was
"B"
pry(#<TestCallbacks>)> test.grade_change
nil

まとめ

  • {attr_name}_wasのようなメソッドはデータの更新完了後は変更前のデータ取れませんが、after_saveのタイミングであれば変更前のデータ取れるので何かと使えるタイミングが多いんじゃないかなと思いました
  • この辺りのメソッドの面白い活用事例などありましたら教えていただきたいです
    • 特にこの子{attr_name}_will_change!
86
61
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
86
61