🐕
ActiveRecord で特定のレコードを更新できないようにする
ActiveRecord の特定のカラムで『これは最初に割り当てた以降は変更してほしくない!』みたいな扱いをしたいことが稀によくあります。
こういうのを機械的に更新できないようにする場合に attr_readonly
が利用できます。
class User < ActiveRecord::Base
# name と created_at を更新不可にする
attr_readonly :name, :created_at
end
homu = User.create!(name: "homu", age: 14)
# 値を割り当てようとすると例外が発生する
# error: `_write_attribute': name (ActiveRecord::ReadonlyAttributeError)
homu.name = "mami"
p homu.name # => "mami"
また update!
に関しても同様に例外になります。
# update! に関しても同様
# error: `_write_attribute': name (ActiveRecord::ReadonlyAttributeError)
homu.update!(name: "mami")
p homu.reload.name # => "homu"
また attr_readonly
のカラムに対して値を割り当てたときに例外が発生するかどうかは config.active_record.raise_on_assign_to_attr_readonly
や ActiveRecord.raise_on_assign_to_attr_readonly
で制御できます。
# false で例外が発生しなくなる
ActiveRecord.raise_on_assign_to_attr_readonly = false
class User < ActiveRecord::Base
attr_readonly :name, :created_at
end
homu = User.create!(name: "homu", age: 14)
# ここで値を割り当ててもエラーにならないが実際には値は更新されていない
homu.name = "mami"
homu.save!
p homu.reload.name # => "homu"
raise_on_assign_to_attr_readonly
のデフォルト値は以下のように設定されています。
| Rails | 値 |
| 7.0 以前 | false |
| 7.1 以降 | true |
ちなみに #update_columns
の場合は raise_on_assign_to_attr_readonly
の設定によらずに例外が発生します。
ActiveRecord.raise_on_assign_to_attr_readonly = false
# error: `verify_readonly_attribute': name is marked as readonly (ActiveRecord::ActiveRecordError)
homu.update_columns(name: "mami")
Discussion