使用has_one关联的Rails方法中的NoMethodError

时间:2012-04-18 05:32:02

标签: ruby-on-rails associations models has-one

这是我的代码:

//在swimmer.rb(模型)中:

    belongs_to :user

//在user.rb(model)中:

    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 %>

如果一个游泳者对象的user_id与游泳者#controller方法中的@swimmer实例变量相匹配,因为有一个登录用户(使用Devise gem)并且已经为该用户创建了一个游泳者,那么该个人资料视图按预期工作。如果没有,页面显示错误:

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

但是由于配置文件视图具有if / else条件,我希望缺少与登录用户关联的swimmer对象来强制视图显示else内容。显然,“Swimmer.find_by_user_id(current_user)”方法正在NilClass中创建一个nil对象。我如何得到它,以便它不会创建任何东西,从而带来其他条件?

回购位于https://github.com/drollwit/vst2/tree/ver2。这是一个练习,而不是一个真正的项目。这里可能有一个简单的答案,但我无法弄明白(仍在学习Rails基础知识)。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分: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为零,并且以下行失败,因为您在nil上调用方法'nickname'。

一个简单的解决方法如下:

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

如果@swimmer不存在,@ simmwer_nickname和@swimmer_gender将设置为nil。请参阅http://api.rubyonrails.org/classes/NilClass.html#method-i-try

就个人而言,我不会像这样在控制器中分配这些额外的实例变量。我会把它移到视图中,或者也许是帮助者。

答案 1 :(得分:1)

错误原因存在于以下代码行中。

@swimmer = Swimmer.find_by_user_id(current_user)

它永远不会根据user_id.Because

找到Swimmer
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}"