我怎样才能减少我的填充方法的冗长程度?

时间:2013-07-26 16:32:10

标签: ruby-on-rails ruby refactoring

我写了一个表单对象来填充Order,Billing和Shipping Address对象。 populate方法看起来非常冗长。由于表单字段不直接对应于地址属性,因此我不得不手动分配它们。例如:

shipping_address.name = params[:shipping_name]
billing_address.name  = params[:billing_name]

这是对象。请注意,为简洁起见,我剪切了大多数地址字段和验证以及其他一些代码。但这应该给你一个想法。请注意填充方法:

class OrderForm
  attr_accessor :params

  delegate :email, :bill_to_shipping_address, to: :order
  delegate :name, :street, to: :shipping_address, prefix: :shipping
  delegate :name, :street, to: :billing_address,  prefix: :billing

  validates :shipping_name, presence: true
  validates :billing_name,  presence: true, unless: -> { bill_to_shipping_address }

  def initialize(item, params = nil, customer = nil)
    @item, @params, @customer = item, params, customer
  end

  def submit
    populate
    # snip
  end

  def order
    @order ||= @item.build_order do |order|
      order.customer = @customer if @customer
    end
  end

  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]

    shipping_address.name          = params[:shipping_name]
    shipping_address.street        = params[:shipping_street]
    # Repeat for city, state, post, code, etc...

    if order.bill_to_shipping_address?
      billing_address.name          = params[:shipping_name]
      billing_address.street        = params[:shipping_street]
      # Repeat for city, state, post, code, etc...
    else
      billing_address.name          = params[:billing_name]
      billing_address.street        = params[:billing_street]
      # Repeat for city, state, post, code, etc...
    end
  end
end

这是控制器代码:

  def new
    @order_form = OrderForm.new(@item)
  end

  def create
    @order_form = OrderForm.new(@item, params[:order], current_user)
    if @order_form.submit
      # handle payment
    else
      render 'new'
    end
  end

Noe我对accepts_nested_attributes_for不感兴趣,它提出了几个问题,因此我编写了表单对象。

4 个答案:

答案 0 :(得分:2)

怎么样

class Order < ActiveRecord::Base
  has_one :shipping_address, class_name: 'Address'
  has_one :billing_address, class_name: 'Address'
  accepts_nested_attributes_for :shipping_address, :billing_address
  before_save :clone_shipping_address_into_billing_address, if: [check if billing address is blank]

然后,当您设置表单时,可以为两个Address对象设置fields_,然后完全填充populate方法。

答案 1 :(得分:2)

def populate
  order.email = params[:email]
  shipping_params = %i[shipping_name shipping_street]
  billing_params = order.bill_to_shipping_address? ?
   shipping_params : %i[billing_name billing_street]

  [[shipping_address, shipping_params], [billing_address, billing_params]]
  .each{|a, p|
     a.name, a.street = params.at(*p)
  }
end

答案 2 :(得分:1)

可能的解决方法是使用变量来检索那些匹配的参数,如下所示:

def populate
    order.email = params[:email]

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

    #set a default state
    shipping_or_billing = "shipping_"
    #or use a ternary here...
    shipping_or_billing = "billing_" if order.bill_to_shipping_address?

    billing_address.name                    = params["shipping_or_billing" + "name"]
    billing_address.street                = params["shipping_or_billing" + "street"]
    ...
end

答案 3 :(得分:1)

您的地址类应该有一个方法可以设置它将作为参数接收的hash的所有地址属性的值。

这样,您的populate方法只检查order.bill_to_shipping_address?,并将正确的字典传递给我建议的方法。

另一方面,该方法只需将hash中的值分配给正确的属性,而无需进行条件检查。