2011-09-25 91 views
1

我有型號:Rails的 - 問題重構控制器的嵌套屬性創建

Transaction has_many :credits, :debits 
Credit belongs_to :transaction 
Debit belongs_to :transaction 

每個學分必須有一個平衡的借方,反之亦然。

我目前(成功)具有以下內幕交易的create方法實現這一目標:

@transaction = Transaction.new(params[:transaction]) 

Transaction.transaction do 

    # Balance debits with credits (Sales) 
    if params[:balance_transaction] == 'credit' 
    @transaction.credits.each do |credit| 
     @transaction.debits.push(Debit.new({ 
     :quantity => 0, 
     :cost_per_unit => 0, 
     :description => 'Balancing Debit', 
     :amount => credit.amount, 
     :account_id => 23 #Get from settings in future to allow users to choose Debtor account 
     })) 
    end 
    elsif params[:balance_transaction] == 'debit' 
    @transaction.debits.each do |debit| 
     @transaction.credits.push(Credit.new({ 
     :quantity => 0, 
     :cost_per_unit => 0, 
     :description => 'Balancing Credit', 
     :amount => credit.amount, 
     :account_id => 43 #Get from settings in future to allow users to choose Creditor account 
     })) 
    end 
    else 
    raise ActiveRecord::Rollback # There's no balancing transaction. Don't save it! 
    end 

end 

我試圖通過更換@transactions.credits.push(...) with debit.balancing_credit並把在下面的移動平衡借記/貸記創作到借記/貸記款借記型號:

def balancing_credit 
    transaction.credits.new({ 
    :quantity => 0, 
    :cost_per_unit => 0, 
    :description => 'Balancing Debit', 
    :amount => amount, 
    :account_id => 43 #Get from settings in future to allow users to choose Creditor account 
    }) 
end 

我認爲這是非常簡單的重構,但它拋出了一個undefined method 'debits' for nil:NilClass錯誤。似乎它看起來在數據庫中尚未保存的交易,以創建平衡功勞?難道我做錯了什麼?

回答

1

你說得對,這樣的機制應該屬於模型,而不是控制器。你可以對你的交易模型before_save回調:

class Transaction 
    after_save :balance_operations 

    def balance_operations 
    if credits 
     credits.each do|credit| 
     debit = debits.build (#do all your stuff here. build() automaticly fills the transaction_id field of your new debit with the proper id) 
     return false unless debit.save 
     end 
    if debits # can use elsif if mutually exclusive conditions 
     # same thing as above 
    end 
    end 
end 

這依賴於一個事實,即回調鏈被包裹在一個ActiveRecord :: Base.transaction。如果回調返回false,ActiveRecord將執行回滾。有關更多信息,請參閱「交易」一章here

如果您在一次交易中有很多操作,您也可以查看a look at this to improve performance

編輯:你也可以添加validates_associated :debit, :credits到模型

+0

感謝隊友。工作很好。 還檢出了有關提高性能的鏈接(是的,我使用事務性的pgsql)。不知道那寶石,有趣的東西。乾杯。 – Roganartu

+1

經過進一步測試後,發現它並未在交易項下保存平衡借記卡/貸項。將transaction_id留空。將其更改爲'after_save',將第二個'if'改爲'elsif'並使用'debits.new'而不是'Debit.new'。現在可以正常工作,並且整個事情都被封裝在事務中,因此COMMIT調用不會在after_save之後。 – Roganartu

+0

我的不好。我總是認爲這些事情顛倒了。您是對的,顯然您的相關借記和貸項不能正確引用未保存的交易,因此沒有ID。編輯答案以匹配此...請注意語法中的細微變化。感謝您的反饋。 –