動かざることバグの如し

近づきたいよ 君の理想に

Railsでモデルのカラムのデフォルト値をセットする方法

データベースに記述する

そもそもRails側でやらなくても、データベースにデフォルト値をセットする機能が備わっているのでそっちを使う。

マイグレーションで書くとこんな感じ

create_table :posts do |t|
  t.string :name, default: "nanashi"
  t.timestamps
end

試してみる。しっかりとデフォルト値が設定されているのがわかる。

Post.new.name
=> "nanashi"

DBに書くのでRailsに依存しないメリットがありつつ、既存のデータベースについてはマイグレーションしなきゃいけないし、仕様変更のためにスキーマを変えなきゃいけないのはちょっと面倒かも。。

attributeを使う

Rails5からActiveRecordにattributes APIというのが追加された。

これを使うとモデル内にデフォルト値をセットできる。

class Post < ApplicationRecord
  attribute :name, :string, default: 'nanashi'
end

試してみる

Post.new.name
=> "nanashi"

詳しいドキュメントは以下

一番シンプルでかつモデル内に記述できるので相当強い方法だが、Rails5以上でないと使えないぐらいしかデメリットが出てこない。。。。使おうな

after_initializeを使う

結論から言うと、この方法は副作用が大きいので推奨されてない しかし実装が簡単なのと、とっつきやすい点から結構使われてしまっている方法

RailsActiveRecordにはいくつもコールバックが用意されていて、after_initialize()でデフォルト値を入れてしまおうというやり方である。

class Post < ApplicationRecord
  after_initialize :set_default, if: :new_record?

  private
  def set_default
    self.name ||= "nanashi"
  end
end

なぜ new_record? が必要かというと、なにもafter_initializeが走るのはモデルで新しいレコードのインスタンスを生成したときだけではなく、Post.all とかで既存のDBから取得したときも当然インスタンスがレコード分だけ生成されるのでafter_initalizeは走ってしまうからである。

ただ、副作用があるといったのはafter_initializeが思わぬときに実行されるケースがあるからで、Railsのバージョンが古いとかそういう話以外では使わないほうが良さそう。。。

ちなみに他の before_validation とか before_save のコールバックでデフォルト値をいれようとするのは禁じ手である

あともう一つぐらいバッドノウハウなやり方があった気がするんだけど()、わすれた。。

参考リンク