82

I have looked through many SO and google posts for generating migration of join table for has many and belongs to many association and nothing work.

All of the solutions are generating a empty migration file.

I am using rails 3.2.13 and I have two tables: security_users and assignments. These are some of things I have try:

rails generate migration assignments_security_users

rails generate migration create_assignments_security_users

rails generate migration create_assignments_security_users_join_table

rails g migration create_join_table :products, :categories (following the official documentation)

rails generate migration security_users_assignments security_user:belongs_to assignments:belongs_to 

Can anyone tell how to create a join table migration between two tables?

gotqn
  • 42,737
  • 46
  • 157
  • 243

5 Answers5

199

To autopopulate the create_join_table command in the command line, it should look like this:

rails g migration CreateJoinTableProductsSuppliers products suppliers

For a Product model and a Supplier model. Rails will create a table titled "products_suppliers". Note the pluralization.

(Side note that generation command can be shortened to just g)

andrewcockerham
  • 2,676
  • 3
  • 23
  • 19
  • 14
    Take care when using CreateJoinTable because when dealing with tables with a prefix like my_products and my_suppliers, it will generate a join table like this my_products_my_suppliers while ActiveRecord expects it to be my_products_suppliers. Then associations like MyProduct.first.my_suppliers will not work! Check https://github.com/rails/rails/issues/13683 - My solution was to keep using CreateJoinTable but add `table_name: :my_products_suppliers` in the migration http://guides.rubyonrails.org/migrations.html – Redoman Oct 21 '14 at 07:18
47

Run this command to generate the empty migration file (it is not automatically populated, you need to populate it yourself):

rails generate migration assignments_security_users

Open up the generated migration file and add this code:

class AssignmentsSecurityUsers < ActiveRecord::Migration
  def change
    create_table :assignments_security_users, :id => false do |t|
      t.integer :assignment_id
      t.integer :security_user_id
    end
  end
end

Then run rake db:migrate from your terminal. I created a quiz on many_to_many relationships with a simple example that might help you.

ziff
  • 339
  • 1
  • 3
  • 16
Powers
  • 18,150
  • 10
  • 103
  • 108
  • 4
    If you do it this way, make sure you add ```null: false``` to the field definitions. For example: ```t.integer :assignment_id, null: false```. This will protect against ghastly situations where you end up with a join table pointing nowhere, your data loses integrity and your code falls over. (Or ends up riddled with ugly and bug-prone guard code). – A Fader Darkly Dec 24 '15 at 12:08
  • 1
    I concur with @Powers and would add that perhaps it's an idea to add a index to those columns? – BenKoshy Jun 23 '16 at 02:34
  • With caveats, Rails can do more of the work for you than this answer suggests. See https://stackoverflow.com/a/20672876/972128 below and the comments to that answer. – kkurian Apr 23 '21 at 19:45
39

I usually like to have the "model" file as well when I create the join table. Therefore I do.

rails g model AssignmentSecurityUser assignments_security:references user:references
Prakash Raman
  • 13,319
  • 27
  • 82
  • 132
3

There's embeded generation for join table in rails

rails g migration AddCityWorkerJoinTable cities:uniq workers

which generates following migration

create_join_table :cities, :workers do |t|
  t.index [:city_id, :worker_id], unique: true
end

❗️ NOTE:

  • models names should go in alphabet order
  • put :uniq only on first param
itsnikolay
  • 17,415
  • 4
  • 65
  • 64
  • 2
    That note is not entirely accurate; model names do not have to be in alphabetical order. I think you are misreading the [Creating a Join Table](https://guides.rubyonrails.org/active_record_migrations.html#creating-a-join-table) documentation, which states `By default, the name of the join table comes from the union of the first two arguments provided to create_join_table, in alphabetical order. To customize the name of the table, provide a :table_name option`. – Allison Feb 22 '22 at 21:28
1

I believe this would be an updated answer for rails 5

create_table :join_table_name do |t|
  t.references :table_name, foreign_key: true
  t.references :other_table_name, foreign_key: true
end
Cody Elhard
  • 655
  • 1
  • 7
  • 17
  • 2
    How would you do this for Rails 6? Running `rails g migration CreateJoinTableBookGenre book genre`, for example, creates 2 commented-out lines: first, `t.index [:book_id, :genre_id]`, and 2nd — the same but with `:book_id` and `:genre_id` swapped. I'm confused; should I pick one or uncomment both? – verified_tinker Jul 21 '20 at 12:12
  • 1
    run `rails g migration AnyNameYouWantToUse` This will generate a migration file, Add the code inside of `def change` (should be empty). Then run `rails db:migrate` – Cody Elhard Jul 21 '20 at 13:31