2012-04-18 87 views
1

這是我的代碼:NoMethodError在導軌方法,使用HAS_ONE關聯

//在swimmer.rb(模型):

belongs_to :user 

//在user.rb(模型):

has_one :swimmer, :dependent => :destroy 
    accepts_nested_attributes_for :swimmer, :allow_destroy => true 
    attr_accessible :swimmer_attributes 

//在swimmers_controller.rb:

def profile 
    @swimmer = Swimmer.find_by_user_id(current_user) 
    @swimmer_nickname = @swimmer.nickname 
    @swimmer_gender = @swimmer.gender 
    @title = "Swimmer Profile for #{@current_user.email}" 
    end 

//在profile.html.erb(在游泳者觀看文件夾)

<% if @swimmer %> 
    <h3><%= @title %></h3> 
    <p>Nickname: <%= @swimmer_nickname %></p> 
    <p>Gender: <%= @swimmer_gender %></p> 
    <% else %> 
    <h3>No Swimmer Profile for<%= current_user.email %></h3> 
    <% end %> 

如果一個游泳者的對象具有在游泳者#控制器方法的@swimmer實例變量相匹配的USER_ID,因爲有登錄的用戶(使用Devise gem),並且爲該用戶創建了游泳者,則配置文件視圖按預期運行。如果沒有,頁面顯示錯誤:

NoMethodError (undefined method `nickname' for nil:NilClass): 
    app/controllers/swimmers_controller.rb:66:in `profile' 

但由於縱斷面圖中有一個if/else條件,我想缺乏與登錄用戶相關聯的游泳者對象來強制視圖以顯示其他內容。顯然,「Swimmer.find_by_user_id(current_user)」方法正在NilClass中創建一個零對象。我如何得到它,以便它不創造任何東西,從而帶來其他條件?

回購是在https://github.com/drollwit/vst2/tree/ver2。這是一個練習,而不是一個真正的項目。這裏可能有一個簡單的答案,但我無法弄清楚(仍然學習Rails基礎知識)。任何幫助,將不勝感激。

回答

1

錯誤原因存在於下面的代碼行中。

@swimmer = Swimmer.find_by_user_id(current_user) 

它永遠不會基於user_id.Because

find_by_user_id 

發現游泳者期待一個ID.Try

@swimmer = Swimmer.find_by_user_id(current_user.id) 

您將獲得游泳對象則不會出現錯誤。

和查看文件可以通過

<% if @swimmer %> 
<h3><%= "Swimmer Profile for #{@current_user.email}" %></h3> 
<p>Nickname: <%= @swimmer.nickname %></p> 
<p>Gender: <%= @swimmer.gender %></p> 
<% else %> 
<h3>No Swimmer Profile for<%= current_user.email %></h3> 
<% end %> 

這可以改善將減少從下面控制器的代碼行。

@swimmer_nickname = @swimmer.nickname 
@swimmer_gender = @swimmer.gender 
@title = "Swimmer Profile for #{@current_user.email}" 
+0

完美。這避免了在視圖中使用#try並使控制器更清潔。我覺得必須有一些顯而易見的東西,我錯過了。我想更大的一點是學習如何正確使用這些find_by動態方法。 – drollwit 2012-04-19 03:56:42

+1

如果這解決了您的問題,請接受答案。 – 2012-04-19 04:34:39

+0

這似乎是這樣回答你的問題,並應標記爲解決。 – Joe 2012-05-12 17:58:34

1

這個問題不看,這是你的個人資料的方法:

def profile 
    @swimmer = Swimmer.find_by_user_id(current_user) 
    @swimmer_nickname = @swimmer.nickname 
    @swimmer_gender = @swimmer.gender 
    @title = "Swimmer Profile for #{@current_user.email}" 
end 

如果無法找到游泳然後@swimmer是零,因爲要調用的方法「綽號」下面的行失敗零。

一個簡單的修正如下:

def profile 
    @swimmer = Swimmer.find_by_user_id(current_user) 
    @swimmer_nickname = @swimmer.try(:nickname) 
    @swimmer_gender = @swimmer.try(:gender) 
    @title = "Swimmer Profile for #{@current_user.email}" 
end 

現在@simmwer_nickname和@swimmer_gender將被設爲零,如果@swimmer不存在。見http://api.rubyonrails.org/classes/NilClass.html#method-i-try

就個人而言,我不會像這樣在控制器中分配這些額外的實例變量。我會將此轉移到視圖或可能的幫手。

+0

工作 - 謝謝!我認爲這是一種方法(而不是視圖)的問題。我將仔細研究try方法的工作原理。至於把所有這些都轉移到輔助方法上,你是對的 - 它不是「瘦身控制器」。我擺弄了一下,把它移到了視圖中,但它看起來像Ruby太多了。我需要研究如何使它成爲輔助方法。 – drollwit 2012-04-18 15:19:53