电子商务发货和结算地址在rails中的一个表中

use*_*515 1 ruby ruby-on-rails ruby-on-rails-3.1 ruby-on-rails-3.2

我正在尝试在同一页面上创建一个包含送货地址和帐单邮寄地址的地址表单.当用户准备结账时,我希望发货地址表和账单地址显示在同一页面上.如果帐单地址与仅发货地址相同的记录应插入地址表中,如果必须插入不同的两个记录,当然必须在订单表shipping_address_id,billing_address_id中进行更新.

只有一个地址模型,如何使用一个提交按钮实现两个表单.以下是我的地址和订单模型

我需要一些帮助来放置控制器我也试图获得每个计费和运输的哈希值

请帮忙!!!

class Address < ActiveRecord::Base
  attr_accessible :name,:first_name,:last_name,:address1,:address2,:city,:state,:zip,:phone,:billing_default,:      user_id,:billing_address, :shipping_address
  belongs_to :user
  has_many :billing_addresses, :class_name => "Order", :foreign_key => "billing_address_id" 
  has_many :shipping_addresses, :class_name => "Order", :foreign_key => "shipping_address_id"

class Order < ActiveRecord::Base
  attr_accessible :cart_id, :order_no, :sales_tax, :shipping_fee,:total,:order_state,:gateway_type,:transaction_id,:transaction_status,:ip_address,:card_verification,:card_number,:billing_address_id,:shippin g_address_id,:first_name,:last_name,:user_id,:card_expires_on,:authenticity_token
  belongs_to :cart
  belongs_to :user
  belongs_to :billing_address, :class_name => "Address"
  belongs_to :shipping_address, :class_name => "Address"
  attr_accessor :card_number
  has_many :transactions, :through => :order_id
  has_many :invoices
  has_many :order_details
Run Code Online (Sandbox Code Playgroud)

Moh*_*mad 13

你会发现这是一个稍微复杂的问题.

首先,问问自己:如果账单和送货地址相同,您真的只想插入一个地址吗?

  1. 客户想要更改送货地址.您将需要逻辑来创建另一个地址记录并将原始记录保留为计费.
  2. 通常,在订单完成后避免更新计费和送货地址,因为它们会危害数据完整性.一旦订单关闭,就是这样; 那些地址应该是固定的.当订单需要不同的送货地址时,请避免订单与开票地址之间存在依赖关系.

现在,假设你要继续前进.

使用嵌套表格

隐藏结算字段,并在表单中添加一个映射到的复选框order.bill_to_shipping_address.默认为要检查.如果未选中,则显示帐单邮寄地址.

  $('input[name="order[bill_to_shipping_address]"]').on 'click', ->
    if $(this).is ':checked'
      $('fieldset.billing_fields').hide()
    else
      $('fieldset.billing_fields').show()
Run Code Online (Sandbox Code Playgroud)

在您的订单模型中:

accepts_nested_attributes_for :shipping_address
accepts_nested_attributes_for :billing_address, reject_if: :bill_to_shipping_address
Run Code Online (Sandbox Code Playgroud)

使用这种方法的缺点是,如果存在验证错误,并且用户碰巧改变主意并将账单转到不同的地址,则账单表格将不会出现,因为它会被拒绝.

使用表单对象

这可能看起来更复杂,但它是一个更清洁的解决方案.

请参阅7个用于重构ActiveRecord对象的模式.

像这样构建表单对象.我从最近为Rails 4应用程序编写的内容中采用了此代码.只是扭转你的关系.在我的情况下,订单有一个帐单地址和一个送货地址; 它不属于他们.

class OrderForm
  include ActiveModel::Model

  def self.model_name
    ActiveModel::Name.new(self, nil, "Order")
  end

  def persisted?
    false
  end

  attr_accessor :params

  delegate :email, :bill_to_shipping_address, to: :order

  # Removed most fields for brevity
  delegate :name, :street, :street_number, to: :shipping_address, prefix: :shipping
  delegate :name, :street, :street_number, to: :billing_address,  prefix: :billing

  # Removed most fields for brevity    
  validates :email, length: { maximum: 60 }, email_format: true
  validates :shipping_name, :shipping_street, presence: true    
  validates :billing_name, presence: true, unless: -> { bill_to_shipping_address }

  def initialize(params = nil)
    @params = params
  end

  def submit
    populate
    if valid?
      order.save!
      true
    else
      false
    end
  end

  def order
    @order ||= Order.new
  end

  private

  def shipping_address
    @shipping_address ||= order.build_shipping_address
  end

  def billing_address
    @billing_address ||= order.build_billing_address
  end

  def populate
    order.email = params[:email]
    order.bill_to_shipping_address = params[:bill_to_shipping_address]

    shipping_address.name = params[:shipping_name]
    # etc...

    unless order.bill_to_shipping_address?
      billing_address.name = params[:billing_name]
      # etc...
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

然后从控制器:

  def new
    @order_form = OrderForm.new
  end

  def create
    @order_form = OrderForm.new(params[:order])
    if @order_form.submit
      # order saved, do whatever
    else
      render 'new'
    end
  end
Run Code Online (Sandbox Code Playgroud)

您的表单现在不关心嵌套属性和属性.这很干净.

= form_for @order do |f|
  = f.text_field :email
  = f.text_field :shipping_street
  = f.text_field :billing_street
  # etc...
Run Code Online (Sandbox Code Playgroud)