0

私は Rails の初心者で、これが StackOverflow への最初の投稿です。

3 つのモデルがあるとします。

class Product < ActiveRecord::Base
  default_scope :order => :title
  has_many :line_items
  has_many :promo_products
  has_many :promotions, :through => :promo_products, :foreign_key => :promotion_id
  before_destroy :ensure_not_referenced_by_any_line_item
  before_destroy :ensure_not_referenced_by_any_promo_product

  validates :title, :presence => true, :uniqueness => true
  validates :description, :presence => true
  validates :price, :numericality => {:greater_than_or_equal_to => 0.01}
  private
  def ensure_not_referenced_by_any_line_item
    if line_items.empty?
      return true
    else
      errors.add(:base, 'Line Items present')
      return false
    end
  end
  def ensure_not_referenced_by_any_promo_product
    if promo_products.empty?
      return true
    else
      errors.add(:base, 'Some promotions are still in effect')
      return false
    end
  end
end

class Promotion < ActiveRecord::Base

  CART_OR_PRODUCT = ['Cart', 'Product']
  PROMOTION_TYPE = ['Percentage based', 'Value based']

  has_many :promo_products
  accepts_nested_attributes_for :promo_products
  has_many :products, :through => :promo_products, :foreign_key => :product_id
  accepts_nested_attributes_for :products
  #attr_accessible :promo_products_attributes, :title, :description, :cart_or_product, :promotion_type, :discount, :minimum_price, :minimum_quantity

  validates :title, :description, :presence => true
  validates :cart_or_product, :inclusion => {:in => CART_OR_PRODUCT, :message =>
  "is invlaid. Please select a valid option"}
  validates :promotion_type, :inclusion => {:in => PROMOTION_TYPE, :message =>
  "is invalid. Please select a valid option"}
  validates :discount, :minimum_price, :numericality => {:greater_than_or_equal_to => 0.00}
  validates :minimum_quantity, :numericality => {:greater_than_or_equal_to => 0}

end

class PromoProduct < ActiveRecord::Base

  belongs_to :promotion
  belongs_to :product
  accepts_nested_attributes_for :products
end

プロモーションの新しいページで、プロモーションの一部になる可能性のある製品のリストを表示したいと思います。ユーザーは、プロモーションのタイプに応じて、0 個、1 個、または複数の製品を選択できます。

Promotions_controller のアクション new では、次のように作成しました。

@promotion.promo_products.build.build_product

プロモーションの _form で、ユーザーが選択できる製品のリストを表示する必要がありました。次のようなネストされたフォームを作成しました。

<%= form_for(@promotion) do |f| %>
  <!-- other promotion fields -->
  <%= f.fields_for :promo_products do |pp| %>
    <%= pp.fields_for :products do |p| %>
      <div class="field">
        <%= f.label "Products" %><br />
        <%= collection_select :promo_product, :product_id, Product.all, :id, :title {:selected => @promotion.product_ids}, {:multiple => true} %>
      </div>
    <% end %>
  <% end %>
<% end %>

2 つの問題があります。

  1. まず、私のコードはエラーをスローします: ArgumentError in PromotionsController#new 名前「products」の関連付けが見つかりません。まだ定義されていますか?PromoProduct モデルの行を次のように変更すると: accept_nested_attributes_for :products を accept_nested_attributes_for :product に変更すると、エラーは発生せず、すべて正常に動作します。
  2. データは promo_product テーブルに保存されません。私は promo_product コントローラに create アクションを次のように持っています:

    def create
      @promotion = current_promotion
      products = Product.select(:id => params[:product_id])
      products.each do |p|
        promo_product = @promotion.promo_products.build(p)
        promo_product.save
      end
      #@promo_product = PromoProduct.new(params[:promo_product])
      redirect_to promotions_path
    end
    

    どうすればそれについて行くことができますか?

ありがとうございました。

4

1 に答える 1

1
  1. 関連テーブル PromoProducts に「accept_nested_attribute_for」を配置しないでください。別のモデルへの関連付けを作成するために使用するモデルに存在する必要があります。"accept_nested_attribute_for" IIRC は、モデルに "[association]_attributes=" メソッドを挿入するだけです。たとえば、このメソッドをプロモーション用の Product クラスに追加すると、"promotion_attributes=" メソッドが Product クラスに挿入されます。次に、ネストされたフォームはこの関数を使用して、モデルと関連付けを表すハッシュを持つ新しいオブジェクトを作成できます。

  2. 上記に基づいて、作成アクションは PromoProduct コントローラーにあるのではなく、Promotion コントローラーにある必要があります。

    <%= form_for(@promotion) do |f| %>
      <!-- other promotion fields -->
      <%= f.fields_for :products do |pp| %>
        <div class="field">
          <%= f.label "Products" %><br />
          <%= collection_select :promo_product, :product_id, Product.all, :id, :title {:selected => @promotion.product_ids}, {:multiple => true} %>
        </div>
      <% end %>
    <% end %>
    

上記の collection_select 行が正しいかどうかは、試してみないとわかりません。ただし、フォームからコントローラーに返されたパラメーターをサーバー コンソール ログで確認することで、これをデバッグできます。基本的に、ネストされたハッシュが表示されるはずです

{:promotion => {:products => ...}}

これについてさらにサポートが必要な場合はお知らせください。私のソリューションでは、select_tag と options_from_collection_for_select の組み合わせを使用しました。(しかし、API ドキュメントを見ずに、これらすべてのオフハンドの動作を思い出すことはできません。)

最後に、:through モデルが必要ですか? through モデルを作成したので、作成アクションでそれを保存する必要があると思います。しかし、PromoProducts テーブルには他の属性がないので、単純に HABTM 関連付けとして残して、レールに残りを処理させたいのでしょうか?

于 2012-07-03T06:10:44.133 に答える