2013-07-26 56 views
0

我寫了一個表單對象來填充一個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 

野老我不感興趣accepts_nested_attributes_for,其中存在幾個問題,因此爲什麼我寫的表單對象。

回答

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 
+0

尼斯和companct +1!是%我只有Ruby 2.0? – Mohamad

+0

是的。它是在Ruby 2.0中引入的。 – sawa

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 
+0

另一種辦法是遍歷特定羣體PARAMS(在這個例子中,我有一個動態的領域 'PARAMS形式[:響應]。每做| question_id,答案|' – creativereason

1

你的地址類也許應該有一個會從hash爲所有的地址屬性值的方法它會收到作爲一個論據。

這樣你的populate方法將只檢查order.bill_to_shipping_address?,他們將正確的字典傳遞給我建議的方法。

另一方面,該方法只需將hash中的值分配給正確的屬性,而無需進行條件檢查。

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] 

然後,當你設置的形式,你可以有fields_for兩個地址對象,側步populate方法完全。

+0

我花了幾個小時尋找進入問題並得出結論嵌套形式是不值得的,它會導致許多問題,爲用戶體驗 – Mohamad

+0

澄清第一個問題:即使用戶已經檢查了'bill to shipping address',錯誤是重複的。問題,如果您使用'reject_if'來結束這項工作,結算表單將在驗證錯誤後消失,因爲它是拒絕的...還有其他幾個問題太長了。 – Mohamad