2016-02-11 73 views
0

我有兩個模型,UserAccount測試關聯模型助手方法rails rspec

# account.rb 
belongs_to :user 

# user.rb 
has_one :account 

Account有一個屬性name。在我看來,我多次打電話current_user.account.name,而且我聽說這不是一個好辦法。所以,我是令人難以置信的迅速,而且我在user.rb

def account_name 
    self.account.name 
end 

在我看來,創建了以下方法所以,現在,我可以簡單地調用current_user.account_name,如果聯想的變化,我只在一個地方進行更新。但我的問題是,我測試這種方法嗎?如果我這樣做,我怎麼測試它,沒有任何神祕的客人?

回答

1

我同意current_user.account.name沒有錯 - 當Sandi Metz會告訴我們「用戶對帳戶知道太多」時,這是一種你無法真正避免的活動記錄。

如果你發現你做了很多的這些方法遍佈用戶模型,你可以使用軌道的委託方法:

delegate :name, :to => :account, :prefix => true 

使用:前綴=> true選項將前綴的方法用戶模型,因此它是account_name。在這種情況下,我會假設你可以編寫一個非常簡單的單元測試方法,它返回只是在帳戶屬性會改變你的測試會失敗,所以你會知道你需要更新委託方法。

+0

感謝'委託'選項。這對我來說是新的。而且,公平的說,使用'current_user.account.name'也許沒什麼問題,然而,你會寫一個測試來測試'account.name'不會改變嗎?與您建議如何爲您的建議代碼編寫測試類似? – thedanotto

+0

如果使用'委託',則只需要測試目標對象(本例中爲Account)就會響應:名稱。 Rails庫測試會處理測試'delegate'方法的味道 - 因此,使用委託將刪除一些方法鏈,並且您將單獨測試在用戶中創建的委託人是否發送了'account_name' (不是'NoMethodError') –

+1

謝謝,這很有道理 – thedanotto

0
  1. 沒有什麼錯current_user.account.name
  2. 有稱其爲current_user.account.name,或使current_user.account_name你調用
  3. 你可能不叫CURRENT_USER沒有什麼區別在模型中,像你說的
  4. 你應該有這方面的天賦,如果你使用它

我個人認爲沒有很好的理由,任何現象。只需使用current_user.account.name即可。

如果您擔心效率問題,請讓current_user返回加入帳戶的用戶。

0

這將會有點偏離主題。所以,如果沒有興趣或有幫助,請提前道歉。

TL; DR:不要將您的模型的知識放在您的視圖中。保持你的控制器瘦。以下是我一直在做的事情。

在我目前的項目中,我一直在努力確保我的視圖完全不知道有關係統其餘部分的任何內容(以減少耦合)。這樣,如果您決定改變執行方式(例如,current_user.account.namecurrent_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結構視圖和管理者之間的契約,而不是視圖和控制器之間。

+0

謝謝你的回答。我非常感激。但是,如果將'name'屬性更改爲'title',您是否會遇到與上述相同的問題,您是否不需要從@results ['current_user'] ['account'] ['name '] to @results ['current_user'] ['account'] ['title']? – thedanotto

+0

你不一定會遇到同樣的問題。即使'name'值實際上來自current_user.account.title,您的散列仍然可以是@results ['current_user'] ['account'] ['name']。您可以更改經理中的哈希構建邏輯,以使用'title'作爲'name'值,並且您的視圖不會更明智。 – jvillian

+0

很酷,我看到這是如何讓生活更輕鬆。你將如何更新與該更改哈希?對不起,如果這是一個複雜的事情來回答 – thedanotto