diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 6d0a2e13ee..5115d4b4d1 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,14 @@
+* Allow to specify a type for created foreign key column in `references` and
+ `add_reference` in migrations.
+
+ Example:
+
+ change_table :vehicle do |t|
+ t.references :station, type: :uuid
+ end
+
+ *Andrey Novikov & Ćukasz Sarnacki*
+
* `create_join_table` removes a common prefix when generating the join table.
This matches the existing behavior of HABTM associations.
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index 98e6795f10..d51bf022a4 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -280,12 +280,19 @@ module ActiveRecord
column(:updated_at, :datetime, options)
end
+ # Adds an appropriately-named _id column as :integer (or whatever :type option specifies),
+ # plus a corresponding _type column if the :polymorphic option is supplied. If :polymorphic
+ # is a hash of options, these will be used when creating the _type column. The :index option
+ # will also create an index, similar to calling add_index.
+ #
+ # references :tagger, polymorphic: true, index: true, type: :uuid
def references(*args)
options = args.extract_options!
polymorphic = options.delete(:polymorphic)
index_options = options.delete(:index)
+ type = options.delete(:type) || :integer
args.each do |col|
- column("#{col}_id", :integer, options)
+ column("#{col}_id", type, options)
column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
index(polymorphic ? %w(id type).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 5814c2b711..8ecb7c0506 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -619,7 +619,8 @@ module ActiveRecord
def add_reference(table_name, ref_name, options = {})
polymorphic = options.delete(:polymorphic)
index_options = options.delete(:index)
- add_column(table_name, "#{ref_name}_id", :integer, options)
+ type = options.delete(:type) || :integer
+ add_column(table_name, "#{ref_name}_id", type, options)
add_column(table_name, "#{ref_name}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
add_index(table_name, polymorphic ? %w[id type].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
end
diff --git a/activerecord/test/cases/adapters/postgresql/uuid_test.rb b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
index d7ff81a382..66006d718f 100644
--- a/activerecord/test/cases/adapters/postgresql/uuid_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/uuid_test.rb
@@ -233,7 +233,7 @@ class PostgresqlUUIDTestInverseOf < ActiveRecord::TestCase
t.string 'title'
end
connection.create_table('pg_uuid_comments', id: :uuid) do |t|
- t.uuid :uuid_post_id, default: 'uuid_generate_v4()'
+ t.references :uuid_post, type: :uuid
t.string 'content'
end
end
diff --git a/activerecord/test/cases/migration/change_table_test.rb b/activerecord/test/cases/migration/change_table_test.rb
index a6d506b04a..3e9d957ed3 100644
--- a/activerecord/test/cases/migration/change_table_test.rb
+++ b/activerecord/test/cases/migration/change_table_test.rb
@@ -72,6 +72,20 @@ module ActiveRecord
end
end
+ def test_references_column_type_with_polymorphic_and_type
+ with_change_table do |t|
+ @connection.expect :add_reference, nil, [:delete_me, :taggable, polymorphic: true, type: :string]
+ t.references :taggable, polymorphic: true, type: :string
+ end
+ end
+
+ def test_remove_references_column_type_with_polymorphic_and_type
+ with_change_table do |t|
+ @connection.expect :remove_reference, nil, [:delete_me, :taggable, polymorphic: true, type: :string]
+ t.remove_references :taggable, polymorphic: true, type: :string
+ end
+ end
+
def test_timestamps_creates_updated_at_and_created_at
with_change_table do |t|
@connection.expect :add_timestamps, nil, [:delete_me]
diff --git a/activerecord/test/cases/migration/references_statements_test.rb b/activerecord/test/cases/migration/references_statements_test.rb
index e9545f2cce..1fdfbdd181 100644
--- a/activerecord/test/cases/migration/references_statements_test.rb
+++ b/activerecord/test/cases/migration/references_statements_test.rb
@@ -55,6 +55,16 @@ module ActiveRecord
assert index_exists?(table_name, :tag_id, name: 'index_taggings_on_tag_id')
end
+ def test_creates_reference_id_with_specified_type
+ add_reference table_name, :user, type: :string
+ assert column_exists?(table_name, :user_id, :string)
+ end
+
+ def test_does_not_create_reference_id_with_specified_type
+ add_reference table_name, :user
+ assert_not column_exists?(table_name, :user_id, :string)
+ end
+
def test_deletes_reference_id_column
remove_reference table_name, :supplier
assert_not column_exists?(table_name, :supplier_id, :integer)