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

How to access Parent of belongs_to attribute


I have the following models:

class League < ApplicationRecord
    has_many :games
end
class Game < ApplicationRecord
    belongs_to :league
end

In my user's show.html.erb I'm trying to display a user's games and the league associated with the game via this snippet game.league.title and this is the view:

<div class="hidden text-center" id="tab-settings">
  <% current_user.games.each do |game| %>
    <ul>
      <li class="w-1/2 mb-4 text-left border-2 rounded-md border-coolGray-900">
        <p class=""><%= game.start_time&.strftime("%a %b %d, %Y %l:%M%P")  %> - <%= game.end_time&.strftime("%l:%M%P")  %></p>
        <p class="mb-2"><%= game.league.title %> - <%= game.home_team %> vs <%= game.away_team %></p>
      </li>
    </ul>
  <% end %>
</div>

game.league.title returns undefined method "title" for nil:NilClass error; however, when I go into the console, game.league.title querys perfectly.

Following the advice given here, I tried the following in the view:

<p class="mb-2"><%= game.league.try(:title) %> etc...</p>

and it works perfectly.

Why does game.league.try(:title) work but game.league.title return an error?


Solution

  • You have bad data. If you want to be able to call game.league without potential nil errors you need the games.league_id column to be defined as NOT NULL. Game.where(league_id: nil) will give you a list of the records with nulls.

    Since Rails 5 belongs_to applies a presence validation to the column by default. This however doesn't prevent null values from sneaking in anyways if you use any of the methods that circumvent validations. Or if the records were created outside of Rails or even in an older version of Rails.

    If you want league to be nullable you can use the safe navigation operator:

    <p class="mb-2"><%= game.league&.title %> etc...</p>
    

    Object#try is an ActiveSupport method that predates the safe navigation operator which was introduced in Ruby 2.3. While it does have its uses the operator generally should be preferred.

    You can also use Module#delegate:

    class Game
      # ...
      delegate :title, to: :game, allow_nil: true, prefix: true
    end
    
    <p class="mb-2"><%= game.league_title %> etc...</p>