0

行に製品、列にサプライヤーを含むフォームがあります。ユーザーは、製品とサプライヤーの組み合わせごとに注文数量を入力できます。

ここに画像の説明を入力

サプライヤーごとに、1 つの注文が作成されます。各 Order には OrderItems が含まれます。OrderItems は、ユーザーが数量を入力するフィールド (製品/サプライヤーの組み合わせ) ごとに作成されます。

送信されたフォームを処理するための手書きのコードがたくさんあります。

以下のコードを DRY する方法はありますか? それとも、全体的により良いアプローチがありますか?

Nested Forms Railscast をチェックアウトしましたが、入力が 2 次元 (サプライヤーと製品の組み合わせ) であるため、accepts_nested_attributes_for をここで使用する方法がわかりません。

class Product < ActiveRecord::Base    
  has_many :order_items
end

class Supplier < ActiveRecord::Base    
  has_many :orders
end

# groups all OrderItems for 1 Supplier
class Order < ActiveRecord::Base    
  has_many :order_items
  belongs_to :supplier

  def self.create_orders_and_order_items(orders)            
    orders.each do |supplier_id, order_items|
      if order_has_order_item?(order_items)
        order = create!(
          :total => 0,
          :supplier_id => supplier_id,
          :order_group_id => order_group.id
        )        
        OrderItem.create_order_items(order, order_items)                
        # update attributes
        order.update(:total => order.order_items.sum(:total))        
      end      
    end
  end

  def self.order_has_order_item?(order_items)
    sum = 0
    order_items.each do |product_id, quantity|
      sum += quantity.to_i
    end
    sum > 0 ? true : false    
  end    
end

# 1 OrderItem per product / supplier combination
class OrderItem < ActiveRecord::Base    
  belongs_to :order
  belongs_to :supplier
  belongs_to :product

  def self.create_order_items(order, order_items)        
    order_items.each do |product_id, quantity|
      if quantity.to_i > 0                        
        order_item = create!(
          :quantity => quantity,
          :product_id => product_id,
          :order_id => order.id,
        )

        # update after creating, because methods called below are only available once object has been instantiated
        order_item.udpate(:total => order_item.calculate_total)
      end
    end
  end  
end

class OrdersController < ApplicationController
  def create
    Order.create_orders_and_order_items(params[:orders])
    respond_to do |format|
      format.html { redirect_to :action => "index" }
    end
  end
end

# view: _form.html.erb
<table>
  <tr>
    <td>Name</td>
    <% @suppliers.each do |supplier| %>
      <td COLSPAN=2><%= supplier.name %></td>
    <% end %>
  </tr>
  <% @products.each do |product| %>
    <tr>
      <td><%= product.name %></td>
      <td><%#= some price %></td>
      <td><%= f.text_field "#{supplier.id}[#{product.id}]", :value => "" %></td>
    </tr>
</table>  

<%= f.submit %>

# params (from memory)
{"orders" => {
  "4" => # supplier_id, 1 Order for each Supplier
    { "13" => "2" } # product_id => quantity, = 1 OrderItem
  }
}
4

2 に答える 2

1

この場合、すべての製品をループする必要はないようです。accepts_nested_attributes_forOrder モデルを追加します。

create_orders_and_order_itemsこれにより、 andが削除されますcreate_order_items

また、OrderItem モデルで数量の検証を使用します。

コードがこのように機能するかどうかはわかりません。ページにアクセスしてすべての製品のリストを表示し、各製品の数量を入力できます。

これの代わりに、追加/削除可能なエントリを用意し、各エントリでユーザーが製品と数量を選択できるようにする必要があります。これはで行われaccepts_nested_attributes_for、あなたの方法はnested_formによって容易になる可能性があります。

于 2013-07-01T15:45:45.750 に答える