ActiveRecord の attribute 更新方法ってどんなものがあって、それぞれどんな違いがあるかご存じですか?
案外色々とあったので表にまとめてみました。リファレンスやソースコードを参考にしつつ、Rails 4.2 でテストしています。
単一の attribute 更新
メソッド | 保存 | バリデーション(*1) | コールバック(*2) | readonly チェック(*3) | updated_at の更新 | 補足 | 使用例 |
---|---|---|---|---|---|---|---|
attribute= | x | - | - | - | - | article.title = 'title' | |
write_attribute | x | - | - | - | - | private メソッド。attribute= はこれを呼び出している。タイプキャストを行う。例えば integer なカラムの attribute に "5" を渡すと数値の 5 に変換する。 |
write_attribute(:title, 'title') write_attribute(:rate, "5")
|
self[:attribute] | x | - | - | - | - | write_attribute の alias。こちらは public。 | article[:title] = 'title' |
raw_write_attribute | x | - | - | - | - | private メソッド。渡された値のタイプキャストを行わない。例えば integer なカラムの attribute に "5" を渡しても数値の 5 に変換しない。 |
raw_write_attribute(:title, 'title') , raw_write_attribute(:rate, "5")
|
update_attribute | o | x | o | o | o | dirty な attribute をすべて保存する。readonly な attribute の場合は例外が発生する。 | article.update_attribute(:title, 'title') |
update_column | o | x | x | o | x | update_columns(name => value) に相当。詳細については次の表へ。 | article.update_column(:title, 'title') |
複数の attribute をまとめて更新
メソッド | 保存 | バリデーション(*1) | コールバック(*2) | readonly チェック(*3) | updated_at の更新 | 補足 | 使用例 |
---|---|---|---|---|---|---|---|
assign_attributes | x | - | - | - | - | article.assign_attributes(title: 'title', body: 'body') |
|
attributes= | x | - | - | - | - | assign_attributes の alias | article.attributes = { title: 'title', body: 'body' } |
update | o | o | o | o | o | save を呼び出す | article.update(title: 'title', body: 'body') |
update_attributes | o | o | o | o | o | update の alias | article.update_attributes(title: 'title', body: 'body') |
update! | o | o | o | o | o | update と同じ処理を行うが、save ではなく save! を呼び出す。そのため例外が発生する。 | article.update!(title: 'title', body: 'body') |
update_attributes! | o | o | o | o | o | update! の alias | article.update_attributes!(title: 'title', body: 'body') |
update_columns | o | x | x | o | x | UPDATE SQL を発行して DB を更新するため最も速い。新しいオブジェクトの場合は例外が発生する。readonly の attribute が更新対象に含まれる場合は例外が発生する。 | article.update_columns(title: 'title', body: 'body') |
クラスメソッド
メソッド | 保存 | バリデーション(*1) | コールバック(*2) | readonly チェック(*3) | updated_at の更新 | 補足 | 使用例 |
---|---|---|---|---|---|---|---|
update | o | o | o | o | o | readonly な attribute を指定すると無視される | Article.update([1, 2], [{ title: 'title1', body: 'body1' }, { title: 'title2', body: 'body2' }]) |
update_all | o | x | x | x | x | 対象のリレーション中すべてのレコードに対して UPDATE SQL を発行する。ActiveRecord のインスタンスを作成しないためバリデーションやコールバックの呼び出し、タイプキャストなどは行われない。そのため、そのまま DB に保存して良い値しか渡すべきではない。 | Article.where(category: 'rails').update_all(title: 'title', body: 'body') |
(*1) 保存時にバリデーションが行われるかどうか。
(*2) 保存時に各種コールバックが呼び出されるかどうか。
(*3) attr_readonly で指定した readonly な attribute が更新されない場合は o。される場合は x。
何かミスにお気づきの際はコメントしていただけると助かります。