Rails: Active Record属性のデフォルト値はコールバックよりもdefaultオプションで設定しよう(翻訳)
Active Recordモデルのインスタンスにデフォルト値を設定する必要が生じたことのある人は、おそらくコールバックでデフォルト値を設定したことがあるでしょう。
実はRails 5.0からもっとよい方法があるのですが、最近まで気づいていませんでした(Mosesに感謝します!)
参考: §2.3 Active Record属性API -- Ruby on Rails 5.0 リリースノート - Railsガイド
Instead of using callbacks, you can use active record attributes to set model default values. pic.twitter.com/CjtxCbaf5d
— Moses Gathuku (@Gathukumose) January 17, 2023
🔗 以下のように書くよりも
デフォルト値をコールバックで設定する。
class Message
before_validation :assign_delivered_at
# ...
private
def assign_delivered_at
delivered_at ||= Time.zone.now
end
end
🔗 以下のように書こう
Active RecordのAttributes APIを使う。
class Message
attribute :delivered_at, default: -> { Time.zone.now }
# ...
end
🔗 そうする理由
コールバックを使う正当な理由があったとしても、コールバックは理解しにくくなる可能性があります。一般にコールバックを減らす方が、後になって驚かされることも少なくなります。
attribute
構文は簡潔かつ明快であり、Railsではこの方法で振る舞いを実行することが推奨されています。
Attributes APIには、他にも「属性の変更トラッキング」「型キャスト」「データベースを用いない属性の追加」といった豊富な機能が揃っていますが、ここではデフォルト値の設定機能だけを使っています。
🔗 そうしない理由があるとすれば
データ整合性を理想的なものにするには、データベーススキーマでデフォルト値を設定する方がより望ましくなります。
デフォルト値をデータベースレベルで設定すれば、Active Recordはその値を保存前の新しいモデルに取り込むので、default
オプションによる方法はおそらく不要です。
データベースレベルでデフォルト値を設定したうえで、さらに上述のdefault
オプションによる方法でActive Recordモデルにデフォルト値を設定すると、Model.new
を呼び出したときにデータベースが設定したデフォルト値が上書きされる点に注意が必要です。Railsでデフォルト値を何らかの理由で意図的に変更するのでない限り、データベースレベルのデフォルト値に加えてdefault
オプションによるデフォルト値も指定する必要はないでしょう。
概要
原著者の許諾を得て翻訳・公開いたします。
日本語タイトルは内容に即したものにしました。
以下のAPIドキュメントもどうぞ。