Rails

ActiveRecord の attribute 更新方法まとめ

More than 3 years have passed since last update.

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。


何かミスにお気づきの際はコメントしていただけると助かります。