Railsでオブジェクトのデフォルト値を設定する最良の方法を見つけようとしています。
私が考えることができる最高のことは、デフォルト値を new
方法は、コントローラーのメソッドに。
これが許容できる場合、またはそれを行うより良い方法がある場合、誰かが何か入力を持っていますか?
Railsでオブジェクトのデフォルト値を設定する最良の方法を見つけようとしています。
私が考えることができる最高のことは、デフォルト値を new
方法は、コントローラーのメソッドに。
これが許容できる場合、またはそれを行うより良い方法がある場合、誰かが何か入力を持っていますか?
回答:
Rubyでは「正しい」とは危険な言葉です。通常、何を行うにも複数の方法があります。そのテーブルのその列のデフォルト値が常に必要であることがわかっている場合は、DB移行ファイルでそれらを設定するのが最も簡単な方法です。
class SetDefault < ActiveRecord::Migration
def self.up
change_column :people, :last_name, :type, :default => "Doe"
end
def self.down
# You can't currently remove default values in Rails
raise ActiveRecord::IrreversibleMigration, "Can't remove the default"
end
end
ActiveRecordはテーブルと列のプロパティを自動検出するため、これにより、標準のRailsアプリでそれを使用するすべてのモデルに同じデフォルトが設定されます。
ただし、特定の場合にのみデフォルト値を設定する場合(たとえば、他のユーザーとテーブルを共有する継承モデルである場合)、モデルオブジェクトが作成されたときにRailsコードで直接実行するのが別のエレガントな方法です。
class GenericPerson < Person
def initialize(attributes=nil)
attr_with_defaults = {:last_name => "Doe"}.merge(attributes)
super(attr_with_defaults)
end
end
次に、を実行するとGenericPerson.new()
、それをPerson.new()
他の何かでオーバーライドしない限り、常に "Doe"属性がトリクルされます。
.new
クラスメソッドで呼び出される新しいモデルオブジェクトで機能します。ActiveRecordの直接呼び出しに関するブログ投稿の議論.allocate
は、データベースからの既存のデータでロードされたモデルオブジェクトに関するものでした。(そして、ActiveRecordがそのように機能するのはひどい考えです、IMO。しかしそれは要点の外です。)
change_column_default :people, :last_name, nil
stackoverflow.com/a/1746246/483520
change_column :people, :last_name, :string, default: "Doe"
SFEleyの回答に基づいて、ここに新しいRailsバージョン用の更新/修正されたものがあります:
class SetDefault < ActiveRecord::Migration
def change
change_column :table_name, :column_name, :type, default: "Your value"
end
end
change_column
かなり「構造化」することができ、逆の操作を推定することはできません。あなたがわからない場合は、単に実行することによってそれをテストdb:migrate
し、db:rollback
右後。同じ結果として受け入れられた回答ですが、少なくともそれは想定されています!
up
とdown
@GoBustoから、上述のように
まず第一に、あなたは過負荷にすることはできません initialize(*args)
、すべてのケースで呼び出されるわけで。
最善の方法は、デフォルトを移行に組み込むことです。
add_column :accounts, :max_users, :integer, :default => 10
2番目に最適な方法は、デフォルトをモデルに配置することですが、これは最初はnilである属性でのみ機能します。boolean
列の場合と同じように、問題が発生する可能性があります。
def after_initialize
if new_record?
max_users ||= 10
end
end
new_record?
デフォルトがdatbaseからロードされた値を上書きしないようにするために必要です。
||=
Railsがinitializeメソッドに渡されたパラメーターをオーバーライドしないようにする必要があります。
after_initiation :your_method_name
.... 2回の使用self.max_users ||= 10
after_initialize do
代わりにdef after_initialize
change_column_default
移行を試すこともできます(Rails 3.2.8でテスト済み):
class SetDefault < ActiveRecord::Migration
def up
# Set default value
change_column_default :people, :last_name, "Smith"
end
def down
# Remove default
change_column_default :people, :last_name, nil
end
end
ActiveRecordオブジェクトを参照している場合、これを行うには2つ(以上)の方法があります。
例えば
class AddSsl < ActiveRecord::Migration
def self.up
add_column :accounts, :ssl_enabled, :boolean, :default => true
end
def self.down
remove_column :accounts, :ssl_enabled
end
end
詳細はこちら:http : //api.rubyonrails.org/classes/ActiveRecord/Migration.html
例えば before_validation_on_create
詳細はこちら:http : //api.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M002147
Ruby on Rails v3.2.8では、after_initialize
ActiveRecordコールバックを使用して、新しいオブジェクトにデフォルト値を割り当てるモデルのメソッドを呼び出すことができます。
after_initializeコールバックは、ファインダーによって検出およびインスタンス化された各オブジェクトに対してトリガーされます。また、after_initializeは、新しいオブジェクトがインスタンス化された後にもトリガーされます(ActiveRecordコールバックを参照)。
したがって、IMOは次のようになります。
class Foo < ActiveRecord::Base
after_initialize :assign_defaults_on_new_Foo
...
attr_accessible :bar
...
private
def assign_defaults_on_new_Foo
# required to check an attribute for existence to weed out existing records
self.bar = default_value unless self.attribute_whose_presence_has_been_validated
end
end
Foo.bar = default_value
インスタンスにattribute_whose_presence_has_been_validated
以前の保存/更新が含まれていない限り、このインスタンスの場合。次にdefault_value
、をビューと組み合わせて使用して、default_value
for bar
属性を使用してフォームをレンダリングします。
せいぜいこれはハッキーです...
属性値をチェックする代わりに、new_record?
組み込みのメソッドをレールで使用します。したがって、上記の例は次のようになります。
class Foo < ActiveRecord::Base
after_initialize :assign_defaults_on_new_Foo, if: 'new_record?'
...
attr_accessible :bar
...
private
def assign_defaults_on_new_Foo
self.bar = default_value
end
end
これはずっときれいです。ああ、Railsの魔法-それは私よりも賢いです。
after_initialize
ここで折り返し電話をすすめますか?コールバックに関するRailsドキュメントには、before_create
追加の条件チェックなしでデフォルト値を設定する例があります
Subscription
after_initialize
なくを使用する理由before_create
は、ユーザーが新しいオブジェクトを作成するときに(ビューで使用するために)ユーザーのデフォルト値を設定するためです。before_create
コールバックが呼び出された後、ユーザーが新しいオブジェクトを務めてきた、彼らの入力を提供し、コントローラに作成するためにオブジェクトを提出しました。次に、コントローラーはbefore_create
コールバックをチェックします。直感に反するように見えますが、それは命名法です- アクションをbefore_create
指しcreate
ます。新しいオブジェクトをインスタンス化してもオブジェクトは生成されませんcreate
。
モデルを扱っている場合は、Rails 5以降でAttriutes APIを使用できます http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute
適切な列名でマイグレーションを追加し、モデルで次のように設定します。
class StoreListing < ActiveRecord::Base
attribute :country, :string, default: 'PT'
end
移行を生成して使用しchange_column_default
、簡潔で可逆的です:
class SetDefaultAgeInPeople < ActiveRecord::Migration[5.2]
def change
change_column_default :people, :age, { from: nil, to: 0 }
end
end
データベースを使用するモデルの特定の属性にデフォルトを設定するだけの場合、SQLのデフォルトの列値を使用することを検討します。使用しているデフォルトのタイプを明確にできますか?
これを処理する方法はいくつかありますが、このプラグインは興味深いオプションのように見えます。
new / initializeをオーバーライドする提案はおそらく不完全です。Railsは(頻繁に)ActiveRecordオブジェクトの割り当てを呼び出します。割り当てを呼び出すと、初期化が呼び出されません。
ActiveRecordオブジェクトについて話している場合は、after_initializeのオーバーライドを確認してください。
これらのブログ投稿(私のものではありません)は役に立ちます。
[編集:SFEleyは、メモリ内の新しいオブジェクトをインスタンス化するときに、Railsが実際にデータベースのデフォルトを確認することを指摘しています-私はそれを認識していませんでした。]
DBでデフォルトの列値として指定されているかのように、デフォルトを設定する必要がありました。したがって、このように動作します
a = Item.new
a.published_at # => my default value
a = Item.new(:published_at => nil)
a.published_at # => nil
引数から属性を設定した後にafter_initializeコールバックが呼び出されるため、属性が設定されたことがないため、または意図的にnilとして設定されたため、属性がnilであるかどうかを知る方法がありませんでした。だから私は少し内部を突く必要があり、この簡単な解決策を思いつきました。
class Item < ActiveRecord::Base
def self.column_defaults
super.merge('published_at' => Time.now)
end
end
私にとってはうまくいきます。(Rails 3.2.x)
提案された回答よりも潜在的にさらに良い/よりクリーンな潜在的な方法は、次のようにアクセッサを上書きすることです:
def status
self['name_of_var'] || 'desired_default_value'
end
ActiveRecord :: Baseのドキュメントの「デフォルトアクセサーの上書き」およびselfの使用に関するStackOverflowの詳細を参照してください。
私はここで同様の質問に答えました..これを行うクリーンな方法はRails attr_accessor_with_defaultを使用することです
class SOF
attr_accessor_with_default :is_awesome,true
end
sof = SOF.new
sof.is_awesome
=> true
更新
attr_accessor_with_defaultはRails 3.2で非推奨になりました。純粋なRubyで代わりにこれを行うことができます
class SOF
attr_writer :is_awesome
def is_awesome
@is_awesome ||= true
end
end
sof = SOF.new
sof.is_awesome
#=> true
attr_accessor_with_default
3.1.0以降のレールでは非推奨
ActiveRecordオブジェクトについて話している場合は、「attribute-defaults」gemを使用します。
ドキュメントとダウンロード:https : //github.com/bsm/attribute-defaults
rails_default_value gemを使用できます。例えば:
class Foo < ActiveRecord::Base
# ...
default :bar => 'some default value'
# ...
end
ActiveRecordモデルのコンストラクターをオーバーライドできます。
このような:
def initialize(*args)
super(*args)
self.attribute_that_needs_default_value ||= default_value
self.attribute_that_needs_another_default_value ||= another_default_value
#ad nauseum
end