If you’ve ever worked on a project with me, you know that I love aliasing and renaming things so that code is more legible. One of the latest discoveries I had was that you can alias join tables so your code makes more sense when you read it out loud.

Scenario

Let’s say that I’m creating an app where a user can own a playlist and also contribute to other user’s playlists. Our schema might look something like below:

playlistuser

A user has many playlists through the owner_id foreign key, but they also make many contributions to playlists through the playlist_user  join table. Vice versa, a playlist has an owner through their owner_id foreign key, but they also have many contributors through the playlist_user join table.

Implementation

There’s actually two steps in implementing the relationship I previously described. The first is to create a direct relationship between the users and playlists through the owner_id foreign key. This can be done by setting up has_many and belongs_to relation:

class Playlist < ActiveRecord::Base
  belongs_to :owner, class_name: "User"
end

class User < ActiveRecord::Base
  has_many :playlists, :foreign_key => 'owner_id'
end

Now we can call something like:

playlist.owner #=> returns the current playlist's owner
user.playlists #=> returns the user's playlists that they own/created

The next step is to alias the has_many through relation with the join table. It turns out it’s pretty straight forward. You just have to declare the has_many with whatever alias you want to give the association, through the join table, and then specify the source, which is the table you want to join to. In this specific case, our code will look as follows:

class Playlist < ActiveRecord::Base
  has_many :playlist_users
  has_many :contributors, through: :playlist_users, source: :user
end

class User < ActiveRecord::Base
  has_many :playlist_users
  has_many :contributions, through: :playlist_users, source: :playlist
end

This association will now allow us to call things like:

playlist.contributors #=> returns the list of users that are allowed to contribute to the playlist
user.contributions #=> returns the list of playlists the the user does not own, but can contribute to

Cool! Now our code is a little bit more legible thanks to a few extra configurations. Until next time, happy coding!