私は次の2つのモデルを持っています
class Sport < ActiveRecord::Base
has_many :charts, order: "sortWeight ASC"
has_one :product, :as => :productable
accepts_nested_attributes_for :product, :allow_destroy => true
end
class Product < ActiveRecord::Base
belongs_to :category
belongs_to :productable, :polymorphic => true
end
製品なしではスポーツは存在できないので、私のsports_controller.rb
には以下がありました。
def new
@sport = Sport.new
@sport.product = Product.new
...
end
after_initialize
を使用して、製品の作成をスポーツモデルに移行しようとしました。
after_initialize :create_product
def create_product
self.product = Product.new
end
モデルがインスタンス化されるたびに(つまり、find
呼び出しから)after_initialize
が呼び出されることをすぐに知りました。ですから、それは私が探していた行動ではありませんでした。
すべてのsport
にproduct
があるという要件をモデル化する方法は何ですか?
ありがとう
あなたが述べたように、コントローラにロジックを入れることが最良の答えかもしれませんが、after_initialize
以下を実行して機能します。
after_initialize :add_product
def add_product
self.product ||= Product.new
end
そのようにして、製品が存在しない場合にのみ製品を設定します。オーバーヘッドの価値がないか、コントローラにロジックがあるよりも明確でない場合があります。
編集:ライアンの答えによると、パフォーマンスの面では次の方が良いでしょう。
after_initialize :add_product
def add_product
self.product ||= Product.new if self.new_record?
end
確かにafter_initialize :add_product, if: :new_record?
は、ここで最もクリーンな方法です。
条件をadd_product関数から除外する
もしあなたがそうするなら self.product ||= Product.new
は、find
を実行するたびに製品を検索します。nilかどうかを確認する必要があるためです。その結果、積極的な読み込みは行われません。これを行うには、新しいレコードが作成されたときにのみ、製品を設定する前にそれが新しいレコードであるかどうかを確認するだけで済みます。
after_initialize :add_product
def add_product
self.product ||= Product.new if self.new_record?
end
基本的なベンチマークとチェックを行ったif self.new_record?
は、目立った形でパフォーマンスに影響を与えないようです。
after_initialize
を使用する代わりに、after_create
はどうですか?
after_create :create_product
def create_product
self.product = Product.new
save
end
それはあなたの問題を解決するように見えますか?
とても近いようです。 after_initializeの呼び出しを完全に廃止できるはずですが、最初に、スポーツモデルが指定した:productと「has_one」関係にある場合、製品モデルも「belong_to」スポーツでなければなりません。これを製品モデルに追加します
belongs_to: :sport
次のステップでは、スポーツモデルを次のようにインスタンス化できるはずです。
@sport = @product.sport.create( ... )
これは、 Association Basics from Ruby on Railsガイド。正確ではない
あなただけのような初期化メソッドをオーバーライドする必要があります
class Sport < ActiveRecord::Base
# ...
def initialize(attributes = {})
super
self.build_product
self.attributes = attributes
end
# ...
end
データベースからレコードがロードされるときに、Initializeメソッドが呼び出されることはありません。上記のコードでは、製品のビルド後に属性が割り当てられていることに注意してください。このような設定では、属性の割り当ては作成された製品インスタンスに影響を与える可能性があります。