1
votes

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
4
Post your Model codes. - Pavan
@Pavan edited my post with Model information. - Xeen
To which view page that code snippet belongs? - Pavan
And also post your controller code. - Pavan
I think that one of your sportists doesn't have a trainer. Check sportists for trainer = nil - Anton Grigoryev

4 Answers

2
votes

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.

2
votes

You can make use of delegate and avoid use of try, if and terniary operator.

Sportist

belongs_to :trainer

delegate :city,  to: :trainer, :allow_nil => true

You need to make small change to your existing code and it will work smoothly :)

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

Seems like you have a sportists that doesn't have a trainer. To avoid this make an if condition like this.

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

And also setting the validation in the Sportist model should resolve the empty trainer_id values

Class Sportist < ActiveRecord::Base

belongs_to :trainer

validates :trainer_id, presence: true

end
0
votes

You can update your code

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

with

   <% @sportists.each do |s| %>
     <%= s.name %> <%= s.surname %>
     <%= s.trainer.present? ? s.trainer.city : "No City Found"  %>
   <% end %>

This will stop the code to throw nil errors