diff options
author | Aleksey Magusev <lexmag@gmail.com> | 2012-07-02 23:41:49 +0400 |
---|---|---|
committer | Rafael Mendonça França <rafaelmfranca@gmail.com> | 2012-07-03 13:25:25 -0300 |
commit | cfb24586b811177666cf0d085e3ab111195fb3ff (patch) | |
tree | 09258d1adfe8aa6ee9c86c005f2d6c9607da13b9 /activerecord | |
parent | eedca4a1467927fce520f567350be0c4b49b9a6f (diff) | |
download | rails-cfb24586b811177666cf0d085e3ab111195fb3ff.tar.gz rails-cfb24586b811177666cf0d085e3ab111195fb3ff.tar.bz2 rails-cfb24586b811177666cf0d085e3ab111195fb3ff.zip |
Add references schema statements
Examples:
add_reference :products, :supplier, polymorphic: true, index: true
remove_reference :products, :user
`add_belongs_to` and `remove_belongs_to` are
acceptable.
Diffstat (limited to 'activerecord')
3 files changed, 149 insertions, 1 deletions
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 2b0ba2f479..8e43193f4b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -441,6 +441,43 @@ module ActiveRecord indexes(table_name).detect { |i| i.name == index_name } end + # Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided. + # <tt>add_reference</tt> and <tt>add_belongs_to</tt> are acceptable. + # + # ====== Create a user_id column + # add_reference(:products, :user) + # + # ====== Create a supplier_id and supplier_type columns + # add_belongs_to(:products, :supplier, polymorphic: true) + # + # ====== Create a supplier_id, supplier_type columns and appropriate index + # add_reference(:products, :supplier, polymorphic: true, index: true) + # + 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) + 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 : nil) if index_options + end + alias :add_belongs_to :add_reference + + # Removes the reference(s). Also removes a +type+ column if one exists. + # <tt>remove_reference</tt>, <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable. + # + # ====== Remove the reference + # remove_reference(:products, :user, index: true) + # + # ====== Remove polymorphic reference + # remove_reference(:products, :supplier, polymorphic: true) + # + def remove_reference(table_name, ref_name, options = {}) + polymorphic = options.delete(:polymorphic) + remove_column(table_name, "#{ref_name}_id") + remove_column(table_name, "#{ref_name}_type") if polymorphic + end + alias :remove_belongs_to :remove_reference + # Returns a string of <tt>CREATE TABLE</tt> SQL statement(s) for recreating the # entire structure of the database. def structure_dump diff --git a/activerecord/test/cases/migration/helper.rb b/activerecord/test/cases/migration/helper.rb index 20f26786f0..768ebc5861 100644 --- a/activerecord/test/cases/migration/helper.rb +++ b/activerecord/test/cases/migration/helper.rb @@ -14,7 +14,7 @@ module ActiveRecord module TestHelper attr_reader :connection, :table_name - CONNECTION_METHODS = %w[add_column remove_column rename_column add_index change_column rename_table] + CONNECTION_METHODS = %w[add_column remove_column rename_column add_index change_column rename_table column_exists? index_exists? add_reference add_belongs_to remove_reference remove_references remove_belongs_to] class TestModel < ActiveRecord::Base self.table_name = :test_models diff --git a/activerecord/test/cases/migration/references_statements_test.rb b/activerecord/test/cases/migration/references_statements_test.rb new file mode 100644 index 0000000000..144302bd4a --- /dev/null +++ b/activerecord/test/cases/migration/references_statements_test.rb @@ -0,0 +1,111 @@ +require "cases/migration/helper" + +module ActiveRecord + class Migration + class ReferencesStatementsTest < ActiveRecord::TestCase + include ActiveRecord::Migration::TestHelper + + self.use_transactional_fixtures = false + + def setup + super + @table_name = :test_models + + add_column table_name, :supplier_id, :integer + add_index table_name, :supplier_id + end + + def test_creates_reference_id_column + add_reference table_name, :user + assert column_exists?(table_name, :user_id, :integer) + end + + def test_does_not_create_reference_type_column + add_reference table_name, :taggable + refute column_exists?(table_name, :taggable_type, :string) + end + + def test_creates_reference_type_column + add_reference table_name, :taggable, polymorphic: true + assert column_exists?(table_name, :taggable_type, :string) + end + + def test_creates_reference_id_index + add_reference table_name, :user, index: true + assert index_exists?(table_name, :user_id) + end + + def test_does_not_create_reference_id_index + add_reference table_name, :user + refute index_exists?(table_name, :user_id) + end + + def test_creates_polymorphic_index + add_reference table_name, :taggable, polymorphic: true, index: true + assert index_exists?(table_name, [:taggable_id, :taggable_type]) + end + + def test_creates_reference_type_column_with_default + add_reference table_name, :taggable, polymorphic: { default: 'Photo' }, index: true + assert column_exists?(table_name, :taggable_type, :string, default: 'Photo') + end + + def test_creates_named_index + add_reference table_name, :tag, index: { name: 'index_taggings_on_tag_id' } + assert index_exists?(table_name, :tag_id, name: 'index_taggings_on_tag_id') + end + + def test_deletes_reference_id_column + remove_reference table_name, :supplier + refute column_exists?(table_name, :supplier_id, :integer) + end + + def test_deletes_reference_id_index + remove_reference table_name, :supplier + refute index_exists?(table_name, :supplier_id) + end + + def test_does_not_delete_reference_type_column + with_polymorphic_column do + remove_reference table_name, :supplier + + refute column_exists?(table_name, :supplier_id, :integer) + assert column_exists?(table_name, :supplier_type, :string) + end + end + + def test_deletes_reference_type_column + with_polymorphic_column do + remove_reference table_name, :supplier, polymorphic: true + refute column_exists?(table_name, :supplier_type, :string) + end + end + + def test_deletes_polymorphic_index + with_polymorphic_column do + remove_reference table_name, :supplier, polymorphic: true + refute index_exists?(table_name, [:supplier_id, :supplier_type]) + end + end + + def test_add_belongs_to_alias + add_belongs_to table_name, :user + assert column_exists?(table_name, :user_id, :integer) + end + + def test_remove_belongs_to_alias + remove_belongs_to table_name, :supplier + refute column_exists?(table_name, :supplier_id, :integer) + end + + private + + def with_polymorphic_column + add_column table_name, :supplier_type, :string + add_index table_name, [:supplier_id, :supplier_type] + + yield + end + end + end +end |