這將會有點偏離主題。所以,如果沒有興趣或有幫助,請提前道歉。
TL; DR:不要將您的模型的知識放在您的視圖中。保持你的控制器瘦。以下是我一直在做的事情。
在我目前的項目中,我一直在努力確保我的視圖完全不知道有關係統其餘部分的任何內容(以減少耦合)。這樣,如果您決定改變執行方式(例如,current_user.account.name
與current_user.account_name
),那麼您不必進入視圖並進行更改。
每個控制器操作都提供一個@results
散列,其中包含視圖需要正確呈現的所有內容。 @results
散列的結構本質上是視圖和控制器之間的契約。
因此,在我的控制器中,@results
可能看起來像{current_user: {account: {name: 'foo'}}}
。在我看來,我會做一些像@results[:current_user][:account][:name]
。我喜歡使用HashWithIndifferentAccess
,所以我也可以做@results['current_user']['account']['name']
,而不是有東西被炸燬或行爲不端。
此外,我一直在將盡可能多的邏輯移出控制器到服務對象(我稱之爲'管理者')。我發現我的經理(這是PORO)比控制器更容易測試。所以,我可能有:
# app/controllers/some_controller.rb
class SomeController
def create
@results = SomeManager.create(params)
if @results[:success]
# happy routing
else
# sad routing
end
end
end
現在,我的控制器超級瘦,不包含路由以外的路由。他們對我的模型一無所知。 (實際上,幾乎所有的控制器動作看起來都與基本上相同的六行代碼完全相同。)再一次,我喜歡這一點,因爲它會創建分離。
當然,我需要經理:
#app/managers/some_manager.rb
class SomeManager
class << self
def create(params)
# do stuff that ends up creating the @results hash
# if things went well, the return will include success: true
# if things did not go well, the return will not include a :success key
end
end
end
所以,在真理的@results
結構視圖和管理者之間的契約,而不是視圖和控制器之間。
感謝'委託'選項。這對我來說是新的。而且,公平的說,使用'current_user.account.name'也許沒什麼問題,然而,你會寫一個測試來測試'account.name'不會改變嗎?與您建議如何爲您的建議代碼編寫測試類似? – thedanotto
如果使用'委託',則只需要測試目標對象(本例中爲Account)就會響應:名稱。 Rails庫測試會處理測試'delegate'方法的味道 - 因此,使用委託將刪除一些方法鏈,並且您將單獨測試在用戶中創建的委託人是否發送了'account_name' (不是'NoMethodError') –
謝謝,這很有道理 – thedanotto