如何使用属于product_category的选项设置订单

目标

我想设置一个订购单,用户可以在其中订购一种产品。填写product_category后,用户可以选择

  • 属于product_category的产品
  • 属于product_category的每个选项的数量。

当前状态

我当前设置代码的方式在必须重新构建表单时引起问题:

  • 当触发验证问题时,(1)product_category,(2)product和(3)选项为空,但是保留仍然保存,从而导致保留两次保存的情况。

=>我知道这是因为我先将保留内容保存在控制器中,然后将选项保存,但是我不知道如何解决此问题(例如,在触发验证以及用户具有然后正确填写表格。)

代码

模型

class Order < ApplicationRecord
  belongs_to :store
  belongs_to :product

  has_many :order_options,dependent: :destroy
  has_many :options,through: :order_options
  accepts_nested_attributes_for :order_options
end

class OrderOption < ApplicationRecord
  belongs_to :option
  belongs_to :order
  accepts_nested_attributes_for :option
end

class Option < ApplicationRecord
  belongs_to :product_category
  has_many :order_options,dependent: :destroy
  has_many :orders,through: :order_options
end

class ProductCategory < ApplicationRecord
  belongs_to :store
  has_many :products,dependent: :destroy
  accepts_nested_attributes_for :products,allow_destroy: true
  has_many :options,dependent: :destroy
  accepts_nested_attributes_for :options,allow_destroy: true
end

order_controller

class OrdersController < ApplicationController
  # skip_before_action :authenticate_user!
  def new
    @user = current_user
    @store = Store.find(params[:store_id])
    @order = Order.new
    @order.build_order_contact
    @product_category_list = @store.product_categories
    @all_options = @store.options
    @products = []
    @options = []
    if params[:product_category].present?
      @products = ProductCategory.find(params[:product_category]).products
      @options = ProductCategory.find(params[:product_category]).options
    else
    end
    if request.xhr?
      respond_to do |format|
        format.json {
        render json: {products: @products,options: @options}
      }
        format.js
      end
    end

    authorize @order
  end

  def create
    @user = current_user
    @store = Store.find(params[:store_id])
    @order = Order.new(order_params)
    @order.store = @store
    authorize @order
    if @order.save
      params[:order_options_attributes].each do |order_option|
        if @option = Option.find_by(id: order_option[:option_id])
          @option_quantity = order_option[:option_quantity]
          @order.options << @option
          order_option = @order.order_options.where(option: @option)
          order_option.update(option_quantity: @option_quantity)
        end
      end
      redirect_to store_path(@store)
    else
      @product_category_list = @store.product_categories
      render 'new'
    end
  end

views / orders / new.js

$("#product_options").html("<%= escape_javascript(render partial: 'option_fields',collection: @options) %>");


$("#dynamic-products").empty();
<% @products.each do |pro| %>
    $("#dynamic-products").append('<option value="<%= pro.id %>"><%= pro.name %></option>')
<% end %>

views / orders / new.html.erb

<%= simple_form_for [@store,@order] do |f|%>
  <%= f.simple_fields_for :products do |product| %>
    <%= product.input :product_category,collection: @product_category_list,prompt: "Select type of product",label:false,input_html:{
      id: "product_category"
    }%>

  <%= f.association :product,collection: @products,input_html:{
    value: @products.object_id,id: "dynamic-products"
  } %>

  <div class="product_category-options" id="product_options">
  </div>
  <% end %>
<% end %>

<script >
  // dynamic products and options for change category
  $(document).on("change","#product_category",function(){
    var product_category = $(this).val();


    $.ajax({
      url: "/stores/<%= @store.id %>/orders/new",method: "GET",// dataType: "json",dataType: "script",data: {product_category: product_category},error: function (xhr,status,error) {
        console.error('AJAX Error: ' + status + error);
      },success: function (response) {
    }
  });
  });
  // dynamic products and option for releading form (e.g. new)
   $(document).ready(function(){
    var product_category = $("#product_category").val();

    $.ajax({
      url: "/stores/<%= @store.id %>/orders/new",dataType: "json",success: function (response) {
    }
  });
  });

</script>

views / orders / _option_fields.html.erb

<div class="product_option order-form-quantity-row border-bottom col col-sm-10">
  <div class="product_option_name order-form-quantity-name">
    <strong>  <%= option_fields.name %></strong>
  </div>

  <div class="order-form-input">
    <%= hidden_field_tag("order_options_attributes[]option_id",option_fields.id ) %>
    <%= select_tag("order_options_attributes[]option_quantity",options_for_select((0..9)),{class:'form-control col col-sm-12'} ) %>

  </div>
</div>
shimin_3333 回答:如何使用属于product_category的选项设置订单

这太复杂了并且被误导了。您真正需要的只是以下内容:

<%= simple_form_for([@store,@order]) do |f| %>
  <% f.simple_fields_for(:order_options) do |ff| %>
    <%= ff.association :option %>
    <%= ff.input :option_quantity %>
  <% end %>
   # ...
<% end %>

class OrdersController
  # Use callbacks to DRY your code
  before_action :set_store,only: [:new,:create,:index]

  def new
    @order = @store.order.new
    # seed the record to create the inputs
    5.times { @order.order_options.build }
    authorize @order
  end

  def create
    @order = @store.orders.new(order_params) do |order|
       order.user = current_user
    end

    if @order.save
       redirect_to @order.store
    else
       render :new
    end
  end

  def set_store
    @store = Store.find(params[:store_id])
  end

  def order_params
    params.require(:order)
          .permit(:foo,:bar,order_options_attributes: [:option_id,:option_quantity]
          )
  end 
end

除非您允许用户即时创建它们,否则不需要接受该选项的嵌套属性,这似乎不是一个好主意,因为单个组件中已经有100个级别的复杂性。

您也不需要执行params[:order_options_attributes].each do |order_option|并遍历嵌套的属性。真的永远不要这样做,因为它首先破坏了使用嵌套属性的整个目的。

当您使用由order_options_attributes=创建的accepts_nested_attributes设置器时,Rails将处理将属性分配给order_options的新实例,并在保存记录之前进行。当您调用保存时,它将立即将所有内容持久保存在事务中,从而避免了您遇到的大多数问题。

您可以在保存之前使用validates_associated触发对order_options的验证。

如果您想使用AJAX进行修饰,请随意。但实际上,您应该首先设置简单且同步的内容,以便了解嵌套属性的工作原理。

通常来说,这段代码似乎快了。首先只设置基础知识(即仅创建产品订单)。测试-重构-然后添加更多功能。如果您一次尝试做所有事情,通常会遇到垃圾箱大火。

本文链接:https://www.f2er.com/3166851.html

大家都在问