はじめに
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!
- 特にこの子