2010-08-21 39 views
5

我確定已經有人問這個問題,但我找不到答案。避免在Rails視圖中使用nil

我有一個項目模型,它與我的客戶模型有belongs_to關係。客戶有一個名字,但是一個項目不一定有客戶。

在我看來,我有這樣的代碼:

<%=h project.client && project.client.name %> 

,因爲如果項目沒有一個客戶端,然後試圖訪問project.client.name導致NoMethodError(nil沒有一個調用的方法name)。

問題是,在視圖中是否可以接受這種類型的零檢查,還是應該尋找其他方法?

回答

10

只需使用

project.client.try(:name) 
+0

我忘了那個...... :)但是,當你穿越5-6個模型時,它仍然會變得很沉重。 :( – DGM 2010-08-21 13:11:20

+3

http://en.wikipedia.org/wiki/Law_of_Demeter – Reactormonk 2010-08-21 14:00:05

+0

@Tass您對德米特法律是正確的,但我認爲這不是正確的實施方式,請在下面看到我的帖子。 – dombesz 2014-01-08 17:06:56

3

我認爲它完全可以接受 - 這是視圖邏輯,您或多或少地根據是否有數據來決定是否顯示視圖的某些部分。

3

我一直在遇到這種情況,而且這很煩人。即使應該從來沒有零,我繼承的髒數據有時會觸發它。

您的解決方案是處理它的一種方法。您也可以在Project中添加一個名爲client_name的方法,該方法會顯示客戶端名稱(如果存在),但是您將模型鏈接在一起的次數超過某些人推薦的範圍。

def client_name 
    client && client.name 
end 

你也可以做一個幫手的方法來做到這一點,但你最終可能會寫很多。 :)

正如下面Skilldrick提到的,這也是有益的補充默認的字符串:

def client_name 
    client ? client.name : "no client" 
end 
+1

更多delegate這絕對是在某些情況下很有用(例如,如果你想要一個默認的名字,如「無客戶端」)。 – Skilldrick 2010-08-21 16:50:27

+1

另一個不使用三元運算符的默認字符串實現:'client.name || 「沒有客戶端」 – Eric 2010-08-21 22:33:47

+0

當然,有人可能會爭辯說,既然最初的問題是討論有一個純粹的mvc模型,那麼通過在模型中放置一個默認的顯示字符串,可能會將更多的視圖邏輯注入到模型中,沒有?這就是爲什麼我會按照提問者的方式做到這一點。但是,這都是風格,這也適用於:)。我只是不願意假設我所做的每一個觀點,我都想要相同的默認字符串,你知道嗎? – jasonpgignac 2010-08-22 03:25:24

0

我哈克的解決辦法是產生一個塊,救出錯誤。許多人會說,使用救援作爲邏輯是非常糟糕的形式。只是不要在實際需要知道何時不存在而不應該這樣的情況下使用它。

在application_helper.rb:

def none_on_fail 
     begin 
      return yield 
     rescue 
      return "(none entered)" 
     end 
    end 

然後在視圖:

<%= none_on_fail { project.client.name } %> 

然後方法根據需要,它可以在任何方法來使用,但它會掩蓋可以如深鏈如果模型/關係/方法存在其他潛在問題。我會將它等同於用火焰噴射器取出碎片。如果使用不當,會非常有效並帶來痛苦的後果。

+1

非常Pythonic :) – Skilldrick 2010-08-21 19:45:29

0

我認爲這些檢查通常可以通過一些想法來消除。這有利於保持視圖代碼更清潔,更重要的是,將邏輯放在視圖圖層之外,這是最佳實踐。一些模板引擎不允許視圖中的任何邏輯。

至少有兩種情況。假設您有一個show操作取決於實例變量。我會說,如果記錄沒有找到控制器不應該呈現HTML,通過重定向或其他。如果在視圖中有一個循環,則使用@array.each do |a| end,以便它不評估數組是否爲空。如果您真的想在視圖中默認應用程序,請嘗試從配置文件中加載它,例如@page_title || #{@APP_CONFIG['page_title']}(見Railscasts #85)。請記住,您可能想稍後更改這些字符串,例如翻譯UI。

這些都是可以避免出現檢查和使用try的情景。如果可能,我會盡量避免它們。如果你無法避免它們,我會把條件檢查放在一個視圖助手中,並添加一個輔助單元測試來驗證(和記錄)兩個代碼路徑。

2

您可以在您的Project課程中使用delegate,這樣您就會尊重Law of demeter這說明您應該「只與您的直接朋友交談」。

project.rb

class Project 
    delegate :name, to: :client, prefix: true, allow_nil: true  
end 

所以這樣的項目對象會知道去哪裏詢問客戶姓名:

#You can now call 
project.client_name 

看到Rails documentation.

相關問題