ActiveRecord でデフォルト値を設定するにはどうすればよいですか?
Pratik の投稿で、醜くて複雑なコードについて説明されているのを見ました。http://m.onkey.org/2007/7/24/モデル内のデフォルト値の設定方法
class Item < ActiveRecord::Base
def initialize_with_defaults(attrs = nil, &block)
initialize_without_defaults(attrs) do
setter = lambda { |key, value| self.send("#{key.to_s}=", value) unless
!attrs.nil? && attrs.keys.map(&:to_s).include?(key.to_s) }
setter.call('scheduler_type', 'hotseat')
yield self if block_given?
end
end
alias_method_chain :initialize, :defaults
end
グーグルで検索してみると、次のような例が見つかりました。
def initialize
super
self.status = ACTIVE unless self.status
end
そして
def after_initialize
return unless new_record?
self.status = ACTIVE
end
移行時にこれを組み込む人も見かけますが、モデル コードで定義する方がよいと思います。
ActiveRecord モデルのフィールドにデフォルト値を設定する標準的な方法はありますか?
ベストアンサー1
利用可能な各メソッドにはいくつかの問題がありますが、after_initialize
次の理由から、コールバックを定義するのが最善の方法であると考えています。
default_scope
新しいモデルの値を初期化しますが、それがモデルを見つけるスコープになります。いくつかの数値を 0 に初期化したいだけであれば、これは望ましいことではありません。- 移行時にデフォルトを定義することもできます (古いバージョンの Rails では、 を呼び出すだけでは機能しません
Model.new
)。 - オーバーライドは
initialize
機能しますが、 を呼び出すことを忘れないでくださいsuper
。 - phusion のようなプラグインを使用するのは、ちょっとばかげています。これは Ruby ですが、デフォルト値を初期化するためだけにプラグインが本当に必要なのでしょうか?
- Rails 3 以降ではオーバーライド
after_initialize
は非推奨です。Rails 3.0.3 でオーバーライドすると、after_initialize
コンソールに次の警告が表示されます。
非推奨の警告: Base#after_initialize は非推奨になりました。代わりに Base.after_initialize :method を使用してください。(/Users/me/myapp/app/models/my_model:15 から呼び出されます)
したがって、次のように関連付けのデフォルトを設定できるだけでなく、after_initialize
属性をデフォルト設定できるコールバックを作成することをお勧めします。
class Person < ActiveRecord::Base
has_one :address
after_initialize :init
def init
self.number ||= 0.0 #will set the default value only if it's nil
self.address ||= build_address #let's you set a default association
end
end
これで、モデルの初期化を探す場所は1 か所だけになりました。誰かがもっと良い方法を思いつくまで、私はこの方法を使っています。
注意:
ブールフィールドの場合は次のようにします。
self.bool_field = true if self.bool_field.nil?
詳細については、この回答に対するポール・ラッセルのコメントを参照してください。
モデルの列のサブセットのみを選択している場合 (つまり、
select
のようなクエリで を使用している場合)、メソッドが 句に含まれていない列にアクセスすると がPerson.select(:firstname, :lastname).all
発生します。次のようにして、このケースを防ぐことができます。MissingAttributeError
init
select
self.number ||= 0.0 if self.has_attribute? :number
ブール列の場合は...
self.bool_field = true if (self.has_attribute? :bool_value) && self.bool_field.nil?
また、Rails 3.2より前の構文は異なることに注意してください(下記のCliff Darlingのコメントを参照)。