2

I'm trying to create an address form with shipping and billing address on same page. When user gets ready for checkout , I want both shipping address form and billing address for to appear on same page. If billing address same as shipping address only record should be inserted into address table , if different two records has to be inserted and of course an update has to take place in orders table shipping_address_id,billing_address_id.

Having only one address model, how do I achieve two forms with one submit button. Below is my model for address and orders

I need some help in putting in controller also I'm trying to get a hash value for each billing and shipping

Please help!!!

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
4

2 回答 2

14

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

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

  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()

在您的订单型号中:

accepts_nested_attributes_for :shipping_address
accepts_nested_attributes_for :billing_address, reject_if: :bill_to_shipping_address

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

使用表单对象

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

请参阅重构 ActiveRecord 对象的 7 种模式

这样构建一个表单对象。我采用了我最近为 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

然后从控制器:

  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

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

= form_for @order do |f|
  = f.text_field :email
  = f.text_field :shipping_street
  = f.text_field :billing_street
  # etc...
于 2013-07-25T16:11:12.663 回答
3

我建议使用一个复选框,以便用户可以指定是使用相同的帐单和送货地址还是键入不同的地址。

在表单文件中,您需要通过以下方式处理嵌套表单:

   = form_for @order do f 
     = f.fields_for :billing_address do |ba|                
       = ba.text_field :address1
       = ba.text_field:address2
       = ba.text_field :city
       = ba.text_field :state
       = ba.text_field :zip
       = ba.text_field :phone
     = f.fields_for :shipping_address do |sa|                
       = sa.text_field :address1
       = sa.text_field:address2
       = sa.text_field :city
       = sa.text_field :state
       = sa.text_field :zip
       = sa.text_field :phone

在您的模型中不要忘记添加:

accepts_nested_attributes_for :shipping_address
accepts_nested_attributes_for :billing_address

并且可能需要将自动构建添加到您的地址关系中

belongs_to :billing_address, :class_name => "Address", autobuild: true
belongs_to :shipping_address, :class_name => "Address", autobuild: true

在控制器创建/更新操作中,您只需要检查复选框值并将它们分配相等,这是一种方法:

@order.shipping_address = @order.billing_address if params[:checkbox_use_same_address] == true
于 2013-12-15T06:08:37.920 回答