Search code examples
ruby-on-railsrubyassociationshas-manybelongs-to

ActionView::Template::Error (undefined method `city' for nil:NilClass):


I'm having belongs_to / has_many relationship between Trainer and Sportists. I'm trying to loop through their values in view like this:

<% @sportists.each do |s| %>
 <%= s.name %> <%= s.surname %>
 <%= s.trainer.city %>
<% end %>

and the Sportist related information works fine, but the trainers - doesn't. I get the error given in the title. If I try to do this in rails console everything works, so relationships should be set fine.

Things I've tried:

<% s.trainers.each do |t| %>
  <%= t.city %>
<% end %>

that gives me undefined method 'trainers' error, and if I try s.trainer I get

#<TRAINER:0X00000004CE7CB0>

So what could be the fix?

EDIT

My models:

Trainer

has_many :sportists
belongs_to :team
accepts_nested_attributes_for :sportists, :reject_if => :all_blank, :allow_destroy => true

Sportist

belongs_to :trainer

Controller

@sportists = Sportist.all

Solution

  • You are getting undefined method 'city' for nil:NilClass in below code:

    <% @sportists.each do |s| %>
     <%= s.name %> <%= s.surname %>
     <%= s.trainer.city %>
    <% end %>
    

    which means that there is a sportists record which doesn't have trainer associated to it. So, for that particular sportlist record s.trainer is nil and you cannot call city on nil object.

    To identify the sportist record for which you don't have an associated trainer, just update the view code as below:

    <% @sportists.each do |s| %>
     <%= s.name %> <%= s.surname %>
     <%= s.trainer.try(:city) %>
    <% end %>
    

    This way even if you don't have an associated trainer record, error would not be raised. In the rendered view, just look for sportlist record which doesn't show any city, that would be the sportlist record without an associated trainer.

    As for the second error undefined method 'trainers' that you received on

    <% s.trainers.each do |t| %>
      <%= t.city %>
    <% end %>
    

    sportlist belongs_to trainer, you only have dynamic method trainer (NOTE singular) available and NOT trainers (NOTE plural). Also, s.trainer would return a single trainer record so you cannot iterate over it with each method as it is not a collection BUT a single record.

    UPDATE

    Ideally, you should not have allowed creation of sportist records without a trainer. You should have added an index on the foreign key trainer_id created on sportlists table. With this you don't even have to use try method and your current code would work as it is.