Rails Relationships — A User by Any Other Name

Dick Ward
2 min readFeb 13, 2018

--

I ran into a problem recently that I didn’t know how to solve. I know. In code, that’s such a commonplace occurrence that it’s not even worth mentioning. The strange thing about this particular problem was that I didn’t even know how to properly research it.

I was making an app called DonorPool, designed to mimic some of the functionality of Patreon, but focused towards charities and non-profits. I wanted to make two different types of relationships for my users and for my charities. A user can be a donor, which has many charities, or a charity manager, which has one. I could have created two different types of users of course, but that seemed silly, and not very DRY.

I searched for “Rails aliasing” and “polymorphic associations” and plenty more. I got a lot of ideas that were similar to what I wanted to do, but nothing exactly it. So in case anyone else is in the same boat as I am, here’s how to handle it.

First, set up a join table for the relationship. This should be in the same format as any old join table. Here’s mine.

class Support < ApplicationRecord
belongs_to :user
belongs_to :charity
end

Boom, easy enough. Nothing we haven’t seen before. Then you’ll create the ‘has many’ relationship, with a few changes. You’re going to tell Rails what you want your second ‘has many’ to be called, and where it’s coming from.

class User < ApplicationRecordhas_many :supports
has_many :supported_charities, through: :supports, source: :charity
end

As you know, we don’t have a table called ‘supported charities.’ But by telling Rails that we’re going to have one with the source of an existing table, ‘charity’, we have the relationship. If we jump into our Rails console to double check, we see that everything is up and running

Rails console showing results of User.first.supported_charities

No fuss, no muss, just some nice, clean code.

--

--

Dick Ward

Full-stack web developer with a flair for the theatrical and a mission to leave the world a better place than I got it. DickWard.com