0

我有一个表格,其中行中的产品和列中的供应商。用户可以输入每个产品/供应商组合的订单数量。

在此处输入图像描述

为每个供应商创建 1 个订单。每个订单都包含 OrderItems。为用户输入数量的每个字段(产品/供应商组合)创建 OrderItems。

有很多手写代码来处理提交的表单。

有没有办法干掉下面的任何代码?还是有更好的方法?

我检查了嵌套表单 Railscast,但我看不出如何在这里使用 Accept_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

回答

还是有更好的方法?

我强烈建议使用表单对象,它基本上可以提取在单独的类中使用多个 AR 模型处理表单的复杂性。

检查7 种模式以分解胖 AR 模型第 3 节。

于 2013-07-01T08:31:43.010 回答
1

在这种情况下,遍历所有产品似乎不是您应该做的。我会添加accepts_nested_attributes_for订单模型。

这会让你删除你的create_orders_and_order_itemsand create_order_items

另外,我会在 OrderItem 模型中使用数量验证。

我不确定您的代码是否像这样工作:您进入您的页面并查看所有产品的列表,然后您可以输入每个产品的数量。

取而代之的是,您应该有可添加/可删除的条目,并且在每个条目中允许用户选择产品和数量。这是通过nested_formaccepts_nested_attributes_for完成的,并且可以为您提供便利。

于 2013-07-01T15:45:45.750 回答