ruby-on-rails-4 - 扩展 Spree::LineItem 以包含 Ticket 对象

标签 ruby-on-rails-4 spree

我的 Ticket 对象引用 Spree::LineItem,它接受 :ticket 的嵌套属性。我已将@@ticket_attributes 添加到强参数和@@line_item_attributes。我已在模型中包含 has_one/belongs_to 关系。为每个 line_item 创建了一个功能嵌套表单以创建票证。

票.rb

class Ticket < ActiveRecord::Base
   belongs_to :line_item
end

line_item_decorator.rb

Spree::LineItem.class_eval do
    has_one :ticket
    accepts_nested_attributes_for :ticket
end

permissed_attributes.rb

module Spree
  module PermittedAttributes
    ATTRIBUTES = [
      ...
      :taxonomy_attributes,
      :ticket_attributes,
      :user_attributes,
      :variant_attributes
    ]

    mattr_reader *ATTRIBUTES

    ...

    @@line_item_attributes = [:id, :variant_id, :quantity, :ticket_attributes]

    ...


    @@ticket_attributes = [:id, :line_item_id, :first_name, :last_name, :start_date, 
    :end_date, :time]

    ...
  end
end

当我单击“结帐”时,我可以看到参数传递并正确嵌套,但控制台向我显示一条消息“不允许的参数:票证”。

Started PATCH "/cart" for 127.0.0.1 at 2014-02-24 09:44:44 -0500
Processing by Spree::OrdersController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"YwCp2xUMd1Zc/v4eWfmMbFMiJdUQo+YYp/86nvSw5nc=", "order"=>{"line_items_attributes"=>{"0"=>{"quantity"=>"2", "ticket"=>{"first_name"=>"Nasty", "last_name"=>"Coffee", "start_date(1i)"=>"2014", "start_date(2i)"=>"2", "start_date(3i)"=>"24"}, "id"=>"23"}}, "coupon_code"=>""}, "checkout"=>""}
  Spree::Preference Load (0.4ms)  SELECT "spree_preferences".* FROM "spree_preferences" WHERE "spree_preferences"."key" = 'spree/frontend_configuration/locale' LIMIT 1
  Spree::Order Load (0.4ms)  SELECT "spree_orders".* FROM "spree_orders" WHERE "spree_orders"."number" IS NULL LIMIT 1
  Spree::Order Load (0.3ms)  SELECT "spree_orders".* FROM "spree_orders" WHERE "spree_orders"."id" = 6 AND "spree_orders"."currency" = 'USD' LIMIT 1
  Spree::Adjustment Load (0.3ms)  SELECT "spree_adjustments".* FROM "spree_adjustments" WHERE "spree_adjustments"."adjustable_type" = 'Spree::Order' AND "spree_adjustments"."adjustable_id" IN (6) ORDER BY spree_adjustments.created_at ASC
  Spree::TokenizedPermission Load (0.3ms)  SELECT "spree_tokenized_permissions".* FROM "spree_tokenized_permissions" WHERE "spree_tokenized_permissions"."permissable_id" = $1 AND "spree_tokenized_permissions"."permissable_type" = $2 ORDER BY "spree_tokenized_permissions"."id" ASC LIMIT 1  [["permissable_id", 6], ["permissable_type", "Spree::Order"]]
Unpermitted parameters: ticket
   (0.1ms)  BEGIN
  Spree::LineItem Load (0.4ms)  SELECT "spree_line_items".* FROM "spree_line_items" WHERE "spree_line_items"."order_id" = $1 AND "spree_line_items"."id" IN (23) ORDER BY created_at ASC  [["order_id", 6]]
  Spree::Payment Load (0.2ms)  SELECT "spree_payments".* FROM "spree_payments" WHERE "spree_payments"."order_id" = $1 AND "spree_payments"."state" = 'completed'  [["order_id", 6]]
  Spree::LineItem Load (0.2ms)  SELECT "spree_line_items".* FROM "spree_line_items" WHERE "spree_line_items"."order_id" = $1 ORDER BY created_at ASC  [["order_id", 6]]
  Spree::Adjustment Load (0.3ms)  SELECT "spree_adjustments".* FROM "spree_adjustments" WHERE "spree_adjustments"."adjustable_id" = $1 AND "spree_adjustments"."adjustable_type" = $2 AND "spree_adjustments"."eligible" = 't' ORDER BY spree_adjustments.created_at ASC  [["adjustable_id", 6], ["adjustable_type", "Spree::Order"]]
  Spree::Adjustment Load (0.5ms)  SELECT "spree_adjustments".* FROM "spree_adjustments" WHERE "spree_adjustments"."order_id" = $1 AND "spree_adjustments"."originator_type" = 'Spree::TaxRate'  [["order_id", 6]]
  Spree::Payment Load (0.4ms)  SELECT "spree_payments".* FROM "spree_payments" WHERE "spree_payments"."order_id" = $1 AND ("spree_payments"."state" NOT IN ('failed', 'invalid'))  [["order_id", 6]]
  CACHE (0.0ms)  SELECT "spree_payments".* FROM "spree_payments" WHERE "spree_payments"."order_id" = $1 AND "spree_payments"."state" = 'completed'  [["order_id", 6]]
  CACHE (0.0ms)  SELECT "spree_adjustments".* FROM "spree_adjustments" WHERE "spree_adjustments"."adjustable_id" = $1 AND "spree_adjustments"."adjustable_type" = $2 AND "spree_adjustments"."eligible" = 't' ORDER BY spree_adjustments.created_at ASC  [["adjustable_id", 6], ["adjustable_type", "Spree::Order"]]
  CACHE (0.0ms)  SELECT "spree_adjustments".* FROM "spree_adjustments" WHERE "spree_adjustments"."order_id" = $1 AND "spree_adjustments"."originator_type" = 'Spree::TaxRate'  [["order_id", 6]]
  CACHE (0.0ms)  SELECT "spree_payments".* FROM "spree_payments" WHERE "spree_payments"."order_id" = $1 AND ("spree_payments"."state" NOT IN ('failed', 'invalid'))  [["order_id", 6]]
   (0.1ms)  COMMIT
something
   (0.1ms)  BEGIN
   (0.1ms)  COMMIT
something 1
  Spree::Shipment Exists (0.2ms)  SELECT 1 AS one FROM "spree_shipments" WHERE "spree_shipments"."order_id" = $1 LIMIT 1  [["order_id", 6]]
  Spree::Activator Load (0.3ms)  SELECT "spree_activators".* FROM "spree_activators" WHERE (starts_at IS NULL OR starts_at < '2014-02-24 14:44:44.387522') AND (expires_at IS NULL OR expires_at > '2014-02-24 14:44:44.387735') AND (event_name LIKE 'spree.order.contents_changed%')
  CACHE (0.0ms)  SELECT "spree_payments".* FROM "spree_payments" WHERE "spree_payments"."order_id" = $1 AND "spree_payments"."state" = 'completed'  [["order_id", 6]]
  CACHE (0.0ms)  SELECT "spree_adjustments".* FROM "spree_adjustments" WHERE "spree_adjustments"."adjustable_id" = $1 AND "spree_adjustments"."adjustable_type" = $2 AND "spree_adjustments"."eligible" = 't' ORDER BY spree_adjustments.created_at ASC  [["adjustable_id", 6], ["adjustable_type", "Spree::Order"]]
  CACHE (0.0ms)  SELECT "spree_adjustments".* FROM "spree_adjustments" WHERE "spree_adjustments"."order_id" = $1 AND "spree_adjustments"."originator_type" = 'Spree::TaxRate'  [["order_id", 6]]
  CACHE (0.0ms)  SELECT "spree_payments".* FROM "spree_payments" WHERE "spree_payments"."order_id" = $1 AND ("spree_payments"."state" NOT IN ('failed', 'invalid'))  [["order_id", 6]]
Redirected to http://localhost:3000/checkout/address
Completed 302 Found in 31ms (ActiveRecord: 4.9ms)

_line_item.html.erb

<% variant = line_item.variant -%>
<%= order_form.fields_for :line_items, line_item do |item_form| -%>
  <tr class="<%= cycle('', 'alt') %> line-item">
    <td class="cart-item-image" data-hook="cart_item_image">
      <% if variant.images.length == 0 %>
        <%= link_to small_image(variant.product), variant.product %>
      <% else %>
        <%= link_to image_tag(variant.images.first.attachment.url(:small)), variant.product %>
      <% end %>
    </td>
    <td class="cart-item-description" data-hook="cart_item_description">
      <h4><%= link_to line_item.name, product_path(variant.product) %></h4>
      <%= variant.options_text %>
      <% if @order.insufficient_stock_lines.include? line_item %>
        <span class="out-of-stock">
          <%= Spree.t(:out_of_stock) %>&nbsp;&nbsp;<br />
        </span>
      <% end %>
      <span class="line-item-description" data-hook="line_item_description">
        <%= line_item_description_text(line_item.description) %>
      </span>
    </td>
    <td class="cart-item-price" data-hook="cart_item_price">
      <%= line_item.single_money.to_html %>
    </td>
    <td class="cart-item-quantity" data-hook="cart_item_quantity">
      <%= item_form.number_field :quantity, :min => 0, :class => "line_item_quantity", :size => 5 %>
    </td>
    <td class="cart-item-total" data-hook="cart_item_total">
      <%= line_item.display_amount.to_html unless line_item.quantity.nil? %>
    </td>
    <td class="cart-item-delete" data-hook="cart_item_delete">
      <%= link_to image_tag('icons/delete.png'), '#', :class => 'delete', :id => "delete_#{dom_id(line_item)}" %>
    </td>

    <%= item_form.fields_for @ticket do |t| %>
      <tr>
        <td class="line_item_ticket">
          <%= t.label :first_name %>
          <%= t.text_field :first_name%>
        </td>
        <td class="line_item_ticket">
          <%= t.label :last_name %>
          <%= t.text_field :last_name%>
        </td>
        <td class="line_item_ticket">
          <%= t.label :start_date %>
          <%= t.date_select :start_date %>
        </td>
      </tr>
    <% end -%>
  </tr> 
<% end -%><% variant = line_item.variant -%>
<%= order_form.fields_for :line_items, line_item do |item_form| -%>
  <tr class="<%= cycle('', 'alt') %> line-item">
    <td class="cart-item-image" data-hook="cart_item_image">
      <% if variant.images.length == 0 %>
        <%= link_to small_image(variant.product), variant.product %>
      <% else %>
        <%= link_to image_tag(variant.images.first.attachment.url(:small)), variant.product %>
      <% end %>
    </td>
    <td class="cart-item-description" data-hook="cart_item_description">
      <h4><%= link_to line_item.name, product_path(variant.product) %></h4>
      <%= variant.options_text %>
      <% if @order.insufficient_stock_lines.include? line_item %>
        <span class="out-of-stock">
          <%= Spree.t(:out_of_stock) %>&nbsp;&nbsp;<br />
        </span>
      <% end %>
      <span class="line-item-description" data-hook="line_item_description">
        <%= line_item_description_text(line_item.description) %>
      </span>
    </td>
    <td class="cart-item-price" data-hook="cart_item_price">
      <%= line_item.single_money.to_html %>
    </td>
    <td class="cart-item-quantity" data-hook="cart_item_quantity">
      <%= item_form.number_field :quantity, :min => 0, :class => "line_item_quantity", :size => 5 %>
    </td>
    <td class="cart-item-total" data-hook="cart_item_total">
      <%= line_item.display_amount.to_html unless line_item.quantity.nil? %>
    </td>
    <td class="cart-item-delete" data-hook="cart_item_delete">
      <%= link_to image_tag('icons/delete.png'), '#', :class => 'delete', :id => "delete_#{dom_id(line_item)}" %>
    </td>

    <%= item_form.fields_for @ticket do |t| %>
      <tr>
        <td class="line_item_ticket">
          <%= t.label :first_name %>
          <%= t.text_field :first_name%>
        </td>
        <td class="line_item_ticket">
          <%= t.label :last_name %>
          <%= t.text_field :last_name%>
        </td>
        <td class="line_item_ticket">
          <%= t.label :start_date %>
          <%= t.date_select :start_date %>
        </td>
      </tr>
    <% end -%>
  </tr> 
<% end -%>

orders_controller#编辑

module Spree
  class OrdersController < Spree::StoreController
    ssl_required :show

    before_filter :check_authorization
    rescue_from ActiveRecord::RecordNotFound, :with => :render_404
    helper 'spree/products', 'spree/orders'

    respond_to :html

    def show
      @order = Order.find_by_number!(params[:id])
    end

    def update
      @order = current_order(lock: true)
      unless @order
        flash[:error] = Spree.t(:order_not_found)
        redirect_to root_path and return
      end

      if @order.update_attributes(order_params)
        puts "something"
        @order.line_items = @order.line_items.select {|li| li.quantity > 0 }
        puts "something 1"
        @order.ensure_updated_shipments
        return if after_update_attributes

        fire_event('spree.order.contents_changed')

        respond_with(@order) do |format|
          format.html do
            if params.has_key?(:checkout)
              @order.next if @order.cart?
              redirect_to checkout_state_path(@order.checkout_steps.first)
            else
              redirect_to cart_path
            end
          end
        end
      else
        respond_with(@order)
      end
    end

    # Shows the current incomplete order from the session
    def edit
      @ticket = Ticket.new
      @order = current_order || Order.new
      associate_user
    end

    # Adds a new item to the order (creating a new order if none already exists)
    def populate
      populator = Spree::OrderPopulator.new(current_order(create_order_if_necessary: true), current_currency)
      if populator.populate(params.slice(:products, :variants, :quantity))
        current_order.ensure_updated_shipments

        fire_event('spree.cart.add')
        fire_event('spree.order.contents_changed')
        respond_with(@order) do |format|
          format.html { redirect_to cart_path }
        end
      else
        flash[:error] = populator.errors.full_messages.join(" ")
        redirect_to :back
      end
    end

    def empty
      if @order = current_order
        @order.empty!
      end

      redirect_to spree.cart_path
    end

    def accurate_title
      if @order && @order.completed?
        Spree.t(:order_number, :number => @order.number)
      else
        Spree.t(:shopping_cart)
      end
    end

    def check_authorization
      session[:access_token] ||= params[:token]
      order = Spree::Order.find_by_number(params[:id]) || current_order

      if order
        authorize! :edit, order, session[:access_token]
      else
        authorize! :create, Spree::Order
      end
    end

    private

      def order_params
        if params[:order]
          params[:order].permit(*permitted_order_attributes)
        else
          {}
        end
      end

      def after_update_attributes
        coupon_result = Spree::Promo::CouponApplicator.new(@order).apply
        if coupon_result[:coupon_applied?]
          flash[:success] = coupon_result[:success] if coupon_result[:success].present?
          return false
        else
          flash.now[:error] = coupon_result[:error]
          respond_with(@order) { |format| format.html { render :edit } }
          return true
        end
      end
  end
end

为什么不被接受?

@Kirt Thorat 非常感谢。我确实看过了,并且参数正在 core/lib/spree/core/controller_helpers/strong_parameters.rb 中设置:

def permitted_order_attributes
          permitted_checkout_attributes + [
            :line_items_attributes => permitted_line_item_attributes 
          ]
        end

我如何包含ticket_attributes?

编辑

我决定忘记票并延长 line_item。但仍然遇到同样的问题。我尝试将 :start_date 属性添加到 order_params 中,如下所示(b/c start_date 是 date_select:

def order_params
      if params[:order]
        params[:order].permit(*permitted_order_attributes, :"start_date(1i)")
      else
        {}
      end
    end

还有这个:

def order_params
      if params[:order]
        params[:order].permit(*permitted_order_attributes, :start_date)
      else
        {}
      end
    end

最佳答案

Spree::OrdersController#update 中,您尝试更新属性ticket,这是不允许的。 因此,允许 ticket 作为 OrdersController(order_params 方法)中 Orders 模型的强参数。

关于ruby-on-rails-4 - 扩展 Spree::LineItem 以包含 Ticket 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21991492/

相关文章:

mysql - ActiveRecord::ConnectionTimeoutError(无法在 5.000 秒内获取数据库连接(已等待 5.000 秒))

ruby-on-rails - 计算 Ruby 中日期时间之间的平均天数

Spree:使用 Deface 替换类属性

ruby-on-rails - 从外部 API 验证 Spree 促销优惠券

ruby-on-rails - Spree为钱找零的安全更新:Class

ruby-on-rails - Rails 4 Minitest 标签

ruby-on-rails - 在 Rails 中创建嵌套资源时没有路由匹配

ruby-on-rails - 有没有办法解决 Rails 删除的迁移?

ruby-on-rails - PayPal Instant Update API 不适用于 HTTPS

ruby-on-rails - 结帐时出现 Spree Commerce 错误 : "We are unable to ship the selected items to your shipping address."