2008-09-15 48 views
5

我到處看到業務邏輯屬於模型,而不是控制器,但限制在哪裏? 我正在玩個人會計應用程序。爲了瘦身控制器的緣故,rails模型應該與其他模型有關嗎?

Account 
Entry 
Operation 

在創建操作如果創建相應的條目和鏈接到帳戶,這樣的操作對於爲例平衡它是唯一有效的買了6包:

o=Operation.new({:description=>"b33r", :user=>current_user, :date=>"2008/09/15"}) 
o.entries.build({:account_id=>1, :amount=>15}) 
o.valid? #=>false 
o.entries.build({:account_id=>2, :amount=>-15}) 
o.valid? #=>true 

現在所示的形式在的情況下給用戶的基本操作被簡化爲隱藏條目的詳細信息,帳戶從默認的5種用戶所要求的操作中選擇(初始賬戶 - >權益對賬,花費資產 - >費用,賺取收入→資產,借貸負債→資產,支付債務資產→負債...)我想要從默認值創建的條目。

我也希望能夠創建更復雜的操作(超過2個條目)。對於第二個用例,我將使用另一種形式來顯示額外的複雜性。第二個用例阻止我在操作中包含借記和貸記字段並刪除Entry鏈接。

這是最好的形式?在操作類的SimpleOperationController使用上面的代碼,因爲我做的那一刻,或定義一個新的方法,所以我可以調用Operation.new_simple_operation(PARAMS [:操作])

是不是應該打破的關注點分離從Operation類實際創建和操作Entry對象?

我不是在尋找的建議對我的扭曲會計準則:)

編輯 - 我似乎沒有表達自己太清楚。 我不太關心驗證。我更關心創建邏輯代碼的位置:

假設控制器上的操作被稱爲花費,當使用支出時,參數散列將包含:金額,日期,描述。借方和貸方帳戶將從被調用的行爲中派生出來,但是我必須創建所有對象。它會更好有

#error and transaction handling is left out for the sake of clarity 
def spend 
    amount=params[:operation].delete(:amount)#remove non existent Operation attribute 
    op=Operation.new(params[:operation]) 
    #select accounts in some way 
    ... 
    #build entries 
    op.entries.build(...) 
    op.entries.build(...) 
    op.save 
end 

或創建上操作的方法,這將使上面的樣子

def spend 
    op=Operation.new_simple_operation(params) 
    op.save 
end 

這肯定會給薄得多的控制器和一個胖模型,但隨後的模型將創建並存儲其他模型的實例,這是我的問題所在。

回答

6

但是然後模型將創建並存儲其他模型的實例,這是我的問題所在。

這是什麼問題?

如果您的'業務邏輯'聲明一個操作必須有一組有效的條目,那麼肯定沒有什麼錯誤讓Operation類知道並處理您的Entry對象。

,如果你把這個你太過分只會得到的問題,並讓您的模型操作的事情,他們需要了解,像EntryHtmlFormBuilder或任何:-)

0

根據每個實體驗證自己以及相互依賴的實體將它們的狀態委派給它們的關聯條目的狀態更容易。在你的情況,例如:

class Operation < ActiveRecord::Base 
    has_many :entries 
    validates_associated :entries 
end 

validates_associated將檢查各相關單位是否有效(在這種情況下,所有參賽作品應該如果操作是有效的)。

試圖驗證整個模型的整個層次結構是非常誘人的,但正如您所說,最容易完成的地方是控制器,它應該更多地作爲請求和響應的路由器在處理業務邏輯。

0

我看它的方式是控制器應該反映最終用戶視圖並將請求轉換爲模型操作和響應,同時進行格式化。在你的情況中,有兩種操作代表了使用默認賬戶/條目進行簡單操作的操作,以及具有用戶選擇條目和賬戶的更復雜操作。表單應該反映用戶視圖(2個表單包含不同的字段),控制器中應該有2個動作來匹配。然而,控制器應該沒有關於如何操作數據的邏輯,只有如何接收和響應。我會在Operation類中使用類方法,它從表單獲取正確的數據並根據需要創建一個或多個對象,或者將這些類方法放在不是AR模型的支持類上,但具有跨越模型的業務邏輯邊界。單獨的實用程序類的優點在於,它將每個模型集中在一個目的上,而不利於實用程序類沒有定義的地方。我把它們放在lib /中,但Rails沒有爲模型助手指定一個地方。

2

虛擬屬性(更多信息herehere)將對此有很大幫助。將整個參數傳遞迴模型使控制器中的事情變得簡單。這將允許您動態構建表單並輕鬆構建條目對象。

class Operation 
    has_many :entries 

    def entry_attributes=(entry_attributes) 
    entry_attributes.each do |entry| 
     entries.build(entry) 
    end 
    end 

end 

class OperationController < ApplicationController 
    def create 
    @operation = Operation.new(params[:opertaion]) 
    if @operation.save 
     flash[:notice] = "Successfully saved operation." 
     redirect_to operations_path 
    else 
     render :action => 'new' 
    end 
    end 
end 

如果一切都無效,保存將失敗。這使我們能夠驗證。因爲每個條目是獨立的,你需要在「創作」檢查所有項目,你可能應該重寫驗證的操作:

class Operation 
    # methods from above 
    protected 
    def validate 
     total = 0 
     entries.each { |e| t += e.amount } 
     errors.add("entries", "unbalanced transfers") unless total == 0 
    end 
end 

現在你會得到一個錯誤信息,告訴金額是關閉的用戶,他們應該修復問題。你可以在這裏獲得真正的喜歡,並通過具體解決問題來增加很多價值,比如告訴他們他們有多少錢。

+0

我最初接受了你的答案,但它假定條目的參數是定義的,而不是這種情況。然後,我將不得不在控制器中創建正確的參數,這與創建對象相同:)但是,您的技巧將在其他地方有用,並在rails 2.2中進行修復,如果IRRC – Jean 2008-09-16 06:20:39

0

如果你關注關於將這個邏輯嵌入到任何特定的模型中,爲什麼不把它們放到一個觀察者類中,這將使您創建相關項目的邏輯與正在觀察的類分離。