Lesson Tuesday

In the last lesson, we covered setting up has_and_belongs_to_many and has_many :through relationships. However, we haven't yet covered how we'll make associations in an application between two objects that should be in a many-to-many relationship.

There are several ways we can do this. We already learned one way when we were working with one-to-many relationships between an album and a song in songs_controller.rb:

controllers/songs_controller.rb
def create
  @album = Album.find(params[:album_id])
  @song = @album.songs.new(song_params)
  if @song.save
    redirect_to album_path(@album)
  else
    render :new
  end
end

This creates a new song which is then added to an album.

We can do this with a many-to-many relationship as well. If there were a many-to-many relationship between albums and songs in the code above, then ActiveRecord would automatically add a new row to the join table that associates albums and songs.

The code above is useful when we want to create a new object and then make a many-to-many association with an object from another class. However, we may not always want to create a new object. What if we already have two existing objects in the database and we want to make a many-to-many association between them?

The following code will make that association between an album and an artist. If you're following along and you've already created a Rails application with a many-to-many relationship between albums and artists from the last lesson, open the Rails console with rails c and type in the following code:

album = Album.create(name: "A Love Supreme")
artist = Artist.create(name: "John Coltrane")
album.artists << artist

In the last line above, we use the << method to make an association between an artist and album. The << method is almost exactly the same as the Array#push method. The main difference is that it can only take one argument, which means we can only push one object at a time. We could use Array#push as well, but the reason we highlight the << method here is because it's regularly referenced in the Rails documentation.

When we call album.artists << artist, ActiveRecord will automatically make the association between the two objects for us. There is no need to save the association.

It doesn't matter whether we make the association by adding an artist to an album or vice versa. ActiveRecord will take care of the association for us. The code below will make exactly the same association in the join table as the code above:

artist.albums << album

However, be careful! If we make the same association twice, there will be multiple rows detailing the association in the join table. Then, if we were to iterate through artist.albums, the same album would be displayed multiple times. It's not because there are duplicate albums — it's because there are duplicates in the join table.

For information on making associations, see the Detailed Association Reference section of the Active Record Associations documentation. Specifically, look at the Methods Added by has_many section to see methods related to many-to-many associations.

Lesson 24 of 34
Last updated August 7, 2022