From d26704a15f88d384dd282425daa832affdb5f8c1 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Tue, 23 Dec 2014 09:14:23 -0700 Subject: Refactor a common class to reduce the duplication for `references` The code for `TableDefinition#references` and `SchemaStatements#add_reference` were almost identical both structurally, and in terms of domain knowledge. This removes that duplication into a common class, using the `Table` API as the expected interface of its collaborator. --- .../abstract/schema_definitions.rb | 113 +++++++++++++++------ .../abstract/schema_statements.rb | 32 +----- 2 files changed, 86 insertions(+), 59 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters/abstract') 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 11c2e8f773..8defc3986f 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -68,6 +68,84 @@ module ActiveRecord end end + class ReferenceDefinition # :nodoc: + def initialize( + name, + polymorphic: false, + index: false, + foreign_key: false, + type: :integer, + **options + ) + @name = name + @polymorphic = polymorphic + @index = index + @foreign_key = foreign_key + @type = type + @options = options + + if polymorphic && foreign_key + raise ArgumentError, "Cannot add a foreign key to a polymorphic relation" + end + end + + def add_to(table) + columns.each do |column_options| + table.column(*column_options) + end + + if index + table.index(column_names, index_options) + end + + if foreign_key + table.foreign_key(foreign_table_name, foreign_key_options) + end + end + + protected + + attr_reader :name, :polymorphic, :index, :foreign_key, :type, :options + + private + + def as_options(value, default = {}) + if value.is_a?(Hash) + value + else + default + end + end + + def polymorphic_options + as_options(polymorphic, options) + end + + def index_options + as_options(index) + end + + def foreign_key_options + as_options(foreign_key) + end + + def columns + result = [["#{name}_id", type, options]] + if polymorphic + result.unshift(["#{name}_type", :string, polymorphic_options]) + end + result + end + + def column_names + columns.map(&:first) + end + + def foreign_table_name + name.to_s.pluralize + end + end + # Represents the schema of an SQL table in an abstract way. This class # provides methods for manipulating the schema representation. # @@ -314,36 +392,9 @@ module ActiveRecord # t.belongs_to(:supplier, polymorphic: true) # # See SchemaStatements#add_reference - def references( - *args, - polymorphic: false, - index: false, - foreign_key: false, - type: :integer, - **options - ) - polymorphic_options = polymorphic.is_a?(Hash) ? polymorphic : options - index_options = index.is_a?(Hash) ? index : {} - foreign_key_options = foreign_key.is_a?(Hash) ? foreign_key : {} - - if polymorphic && foreign_key - raise ArgumentError, "Cannot add a foreign key on a polymorphic relation" - end - + def references(*args, **options) args.each do |col| - column("#{col}_id", type, options) - - if polymorphic - column("#{col}_type", :string, polymorphic_options) - end - - if index - self.index(polymorphic ? %w(type id).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options) - end - - if foreign_key - self.foreign_key(col.to_s.pluralize, foreign_key_options) - end + ReferenceDefinition.new(col, **options).add_to(self) end end alias :belongs_to :references @@ -597,6 +648,10 @@ module ActiveRecord end end + def foreign_key(*args) # :nodoc: + @base.add_foreign_key(name, *args) + end + private def native @base.native_database_types 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 a19bcc86c2..6e42089801 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -645,36 +645,8 @@ module ActiveRecord # # add_reference(:products, :supplier, foreign_key: true) # - def add_reference( - table_name, - ref_name, - polymorphic: false, - index: false, - foreign_key: false, - type: :integer, - **options - ) - polymorphic_options = polymorphic.is_a?(Hash) ? polymorphic : options - index_options = index.is_a?(Hash) ? index : {} - foreign_key_options = foreign_key.is_a?(Hash) ? foreign_key : {} - - if polymorphic && foreign_key - raise ArgumentError, "Cannot add a foreign key to a polymorphic relation" - end - - add_column(table_name, "#{ref_name}_id", type, options) - - if polymorphic - add_column(table_name, "#{ref_name}_type", :string, polymorphic_options) - end - - if index - add_index(table_name, polymorphic ? %w[type id].map{ |t| "#{ref_name}_#{t}" } : "#{ref_name}_id", index_options) - end - - if foreign_key - add_foreign_key(table_name, ref_name.to_s.pluralize, foreign_key_options) - end + def add_reference(table_name, *args) + ReferenceDefinition.new(*args).add_to(update_table_definition(table_name, self)) end alias :add_belongs_to :add_reference -- cgit v1.2.3