Rails Association Tips

by Dan DeMeyere - @dandemeyere

Rails is one of those languages where you can infer how it should interpret code. A more simple way to word that is this: sometimes you'll be coding something for the hundredth time and all of a sudden you'll think to yourself 'I wonder if this will work' and you'll try to change a convention based on your previous experiences with that language. This recently happened to me and I wanted to share what I discovered.

We have a lot of named scopes in our app. Typically our named scopes look something like this:

In that example, our User model has_one :concierge_information (btw, definitely check out our new thredUP Concierge app). While I was creating this scope, I wondered if I could infer which 'joined_via' column I was referencing since I was querying over two tables. So I tried this:

And it worked! Much prettier, right? That example doesn't save a lot of keystrokes, but it should help keep things organized if you're joining across multiple tables and/or querying a lot of ambiguous columns (when you're query references a column name that exists on multiple models you're querying across). While I was writing this, I thought it might be nice to share some other association-related tips I've learned.

ActiveRecord Association Tips

Rails associations are awesome and they come with a lot of built-in class methods/helpers. The basic rule of thumb that I use is that if you're accessing an object's association, you probably have access to the ActiveRecord methods the association's model has. For example:

In that example, you can do any ActiveRecord query on that user's orders as if you were querying a subset of the Order table itself. This can be very handy if you have nested associations.

Object Association Tips

One that I recently came across was the built-in method for creating an associated record that is a has_one association. It ended up just being 'create_#{association name}'. It's not life changing, but it's nice to know. Here it is in action:

In case you're wondering what the has_many version looks like:

This brings up an important note about something I was fuzzy about until recently. When are these objects saved? Obviously a .create() call will write to the DB, but what about when you create/build the object outside of the association and then assign it afterwords? Here are some examples (these are all under the pretense that @user is already stored in the database):

That was helpful for me to learn as unnecessary .save calls result in additional calls to the database.

Lastly, I came across an edge case scenario that I was curious about. If you're using the '<<' operator to associate newly created objects, how do you know if the object you're creating failed? The answer is you don't. However, you can use the .push() method and it will do the same thing as the '<<' operator except that it will return true or false depending on whether the creation was successful or not.