Creating a many to many relationship in Rails

You want a has_and_belongs_to_many relationship. The guide does a great job of describing how this works with charts and everything:

http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association

You will end up with something like this:

# app/models/category.rb
class Category < ActiveRecord::Base
  has_and_belongs_to_many :users
end

# app/models/user.rb
class User < ActiveRecord::Base
  has_and_belongs_to_many :categories
end

Now you need to create a join table for Rails to use. Rails will not do this automatically for you. This is effectively a table with a reference to each of Categories and Users, and no primary key.

Generate a migration from the CLI like this:

bin/rails g migration CreateCategoriesUsersJoinTable

Then open it up and edit it to match:

For Rails 4.0.2+ (including Rails 5.2):

def change
  # This is enough; you don't need to worry about order
  create_join_table :categories, :users

  # If you want to add an index for faster querying through this join:
  create_join_table :categories, :users do |t|
    t.index :category_id
    t.index :user_id
  end
end

Rails < 4.0.2:

def self.up
  # Model names in alphabetical order (e.g. a_b)
  create_table :categories_users, :id => false do |t|
    t.integer :category_id
    t.integer :user_id
  end

  add_index :categories_users, [:category_id, :user_id]
end

def self.down
  drop_table :categories_users
end

With that in place, run your migrations and you can connect Categories and Users with all of the convenient accessors you’re used to:

User.categories  #=> [<Category @name="Sports">, ...]
Category.users   #=> [<User @name="UserA">, ...]
User.categories.empty?

Leave a Comment