Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails migration create_join_table with uuids

Newer versions of rails let you specify that tables should be created with a uuid primary key like so:

create_table :foos, id: :uuid do |t|
  # ...
end

Which is great. And for a long time rails has supported creating join tables like so:

create_join_table :foos, :bars do |t|
  # ...
end

Also great. Except my tables have uuid primary keys and that generates foreign key columns of type integer instead of type uuid.

Looking over the documentation for create_join_table, I can't find anything obvious to change the column type. Is it possible to use create_join_table with uuids?

Or do I have create the join table manually:

create_table :bars_foos, id: false do |t|
  t.uuid :bar_id
  t.uuid :foo_id
end
like image 376
ihaztehcodez Avatar asked Oct 02 '15 16:10

ihaztehcodez


3 Answers

Within Rails 5.0 you can use an additional option column_options on the create_join_table method to specify the type of your id columns. Your migration would then look like:

create_join_table :foos, :bars, column_options: {type: :uuid} do |t|
  t.index [:foo_id, :baar_id]
end
like image 72
anka Avatar answered Nov 10 '22 23:11

anka


I should have looked at the code...

def create_join_table(table_1, table_2, options = {})
  join_table_name = find_join_table_name(table_1, table_2, options)

  column_options = options.delete(:column_options) || {}
  column_options.reverse_merge!(null: false)

  t1_column, t2_column = [table_1, table_2].map{ |t| t.to_s.singularize.foreign_key }

  create_table(join_table_name, options.merge!(id: false)) do |td|
    td.integer t1_column, column_options
    td.integer t2_column, column_options
    yield td if block_given?
  end
end

Columns are explicitly created as integers with no means to change them. Too bad...

like image 44
ihaztehcodez Avatar answered Nov 11 '22 00:11

ihaztehcodez


There is no way of creating join tables with uuids.

As pointed out in the question create_table is the only option. The best way of emulating create_join_tables with uuid is by using create_tables as follows:

  • Run: rails g migration CreateFoosBars bars:references foos:references
  • The command will produce the following output which you will need to modify

generate output

class CreateBarFoos < ActiveRecord::Migration
  def change
    create_table :bars_foos, id: :uuid do |t|
      t.references :bars, foreign_key: true
      t.references :foo, foreign_key: true
    end
  end
end
  • Change id: uuid => id: false
  • Add type: uuid, index: true to the end of the references

final migration

class CreateBarFoos < ActiveRecord::Migration
  def change
    create_table :bars_foos, id: false do |t|
      t.references :bars, foreign_key: true, type: :uuid, index: true
      t.references :foo, foreign_key: true, type: :uuid, index: true
    end
  end
end

It would be good if Rails could add extra support for different id types in create_join_table, this could even be inferred by an existing migration.

Until then hopefully these steps will achieve the same result.

like image 36
ImaginateWayne Avatar answered Nov 11 '22 00:11

ImaginateWayne