DEV Community

Aldo Portillo
Aldo Portillo

Posted on

Association Accessors

Introduction

While working with Ruby on Rails I have encountered a couple tedious things. On my first project in which I was learning Active Record query methods. I was writing a lot of these query methods in erb and couldn't help but think there was a simpler way.

Problem

I was attempting to render names of different models linked through a join table.

So my code looked something like:

<!-- app/views/actor/show.html.erb -->
<%@characters.each{ |character| %>
    <tr>
      <td><%= Movie.where({:id => character.movie_id})at(0).title %></td>
      <td><%= Movie.where({:id => character.movie_id})at(0).year %></td>
      <td><%= Director.where({:id => Movie.where({:id=> character.movie_id}).at(0).director_id}).a(0).name %></td>
      <td><%= character.name %></td>
      <td><a href="/movies/<%= character.movie_id%>">Show details</a></td>
    </tr>
<% } %>
Enter fullscreen mode Exit fullscreen mode

A minimum of 30 minutes were wasted writing that loop in order to avoid typos. That is too long. Luckily, I never have to do that again because of Association Accessors.

Solution

Association Accessors are to models like attribute accessors are to Classes.

On the third table data tag, you can see we are trying to get the name of the director using the movie_id value given by the character.

So we need to do two things:

  1. Create a director getter inside the Movie model
  2. Create a characters getter inside the Actor model

In our Movie model we need to return the director:

# app/models/movie.rb
class Movie < ApplicationRecord
  def director
    my_director_id = self.director_id

    the_director = Director.where({:id => my_director_id}).at(0)

    return the_director
  end
end
Enter fullscreen mode Exit fullscreen mode

Here we are creating a method that returns the director when called. So if we have the director_id we can call the method and chain the key of the value we want.

In our Actor model we need to return the Characters:

class Actor < ApplicationRecord
  def characters
    my_actor_id = self.id

    characters = Character.where({:actor_id => my_actor_id})

    return characters
  end
end
Enter fullscreen mode Exit fullscreen mode

We now created a method that returns the characters when called getting the id of the actor, so we can make our code more legible by using those methods.

<!-- app/views/actor/show.html.erb -->
<% @the_actor.characters.each do |a_character| %>
    <% the_movie = a_character.movie %>
    <tr>
      <td><%= the_movie.title %></td>
      <td><%= the_movie.year %></td>
      <td><%= the_movie.director.name %></td>
      <td><%= a_character.name %></td>
      <td><a href="/movies/<%= the_movie.id %>"> Show details</a></td>
    </tr>
  <% end %>
Enter fullscreen mode Exit fullscreen mode

Conclusion

You should be using association accessors when creating your models. They take time to create but they will save you time as your project scales.

Top comments (0)