diff options
Diffstat (limited to 'activerecord/lib/active_record')
6 files changed, 69 insertions, 30 deletions
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb index 1d7b3e90c0..c1ef86a95b 100644 --- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb +++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb @@ -43,7 +43,7 @@ module ActiveRecord constraint = build_constraint(klass, table, key, foreign_table, foreign_key) - predicate_builder = PredicateBuilder.new(klass, table) + predicate_builder = PredicateBuilder.new(TableMetadata.new(klass, table)) scope_chain_items = scope_chain[scope_chain_index].map do |item| if item.is_a?(Relation) item diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 65ca1f6fd3..cb53fb0d44 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -249,12 +249,12 @@ module ActiveRecord end def predicate_builder # :nodoc: - @predicate_builder ||= PredicateBuilder.new(self, arel_table) + @predicate_builder ||= PredicateBuilder.new(table_metadata) end private - def relation #:nodoc: + def relation # :nodoc: relation = Relation.create(self, arel_table, predicate_builder) if finder_needs_type_condition? @@ -263,6 +263,10 @@ module ActiveRecord relation end end + + def table_metadata # :nodoc: + TableMetadata.new(self, arel_table) + end end # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index b0a4f27049..65c4c11e64 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -8,8 +8,9 @@ module ActiveRecord require 'active_record/relation/predicate_builder/range_handler' require 'active_record/relation/predicate_builder/relation_handler' - def initialize(klass, table) - @klass = klass + delegate :resolve_column_aliases, to: :table + + def initialize(table) @table = table @handlers = [] @@ -22,16 +23,6 @@ module ActiveRecord register_handler(AssociationQueryValue, AssociationQueryHandler.new(self)) end - def resolve_column_aliases(hash) - hash = hash.dup - hash.keys.grep(Symbol) do |key| - if klass.attribute_alias? key - hash[klass.attribute_alias(key)] = hash.delete key - end - end - hash - end - def build_from_hash(attributes) attributes = convert_dot_notation_to_hash(attributes.stringify_keys) expand_from_hash(attributes) @@ -43,11 +34,11 @@ module ActiveRecord # # For polymorphic relationships, find the foreign key and type: # PriceEstimate.where(estimate_of: treasure) - if klass && reflection = klass._reflect_on_association(column) - value = AssociationQueryValue.new(reflection, value) + if table.associated_with?(column) + value = AssociationQueryValue.new(table.associated_table(column), value) end - build(table[column], value) + build(table.arel_attribute(column), value) end def self.references(attributes) @@ -82,17 +73,14 @@ module ActiveRecord protected - attr_reader :klass, :table + attr_reader :table def expand_from_hash(attributes) return ["1=0"] if attributes.empty? attributes.flat_map do |key, value| if value.is_a?(Hash) - arel_table = Arel::Table.new(key) - association = klass._reflect_on_association(key) - builder = self.class.new(association && association.klass, arel_table) - + builder = self.class.new(table.associated_table(key)) builder.expand_from_hash(value) else expand(key, value) diff --git a/activerecord/lib/active_record/relation/predicate_builder/association_query_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/association_query_handler.rb index bda2c02a10..aabcf20c1d 100644 --- a/activerecord/lib/active_record/relation/predicate_builder/association_query_handler.rb +++ b/activerecord/lib/active_record/relation/predicate_builder/association_query_handler.rb @@ -8,11 +8,12 @@ module ActiveRecord def call(attribute, value) queries = {} + table = value.associated_table if value.base_class - queries[value.association.foreign_type] = value.base_class.name + queries[table.association_foreign_type] = value.base_class.name end - queries[value.association.foreign_key] = value.ids + queries[table.association_foreign_key] = value.ids predicate_builder.build_from_hash(queries) end @@ -22,10 +23,10 @@ module ActiveRecord end class AssociationQueryValue # :nodoc: - attr_reader :association, :value + attr_reader :associated_table, :value - def initialize(association, value) - @association = association + def initialize(associated_table, value) + @associated_table = associated_table @value = value end @@ -34,7 +35,7 @@ module ActiveRecord end def base_class - if association.polymorphic? + if associated_table.polymorphic_association? @base_class ||= polymorphic_base_class_from_value end end diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb index 6c103e331f..cfe99072ca 100644 --- a/activerecord/lib/active_record/sanitization.rb +++ b/activerecord/lib/active_record/sanitization.rb @@ -88,7 +88,7 @@ module ActiveRecord # # => "address_street='123 abc st.' and address_city='chicago'" def sanitize_sql_hash_for_conditions(attrs, default_table_name = self.table_name) table = Arel::Table.new(table_name).alias(default_table_name) - predicate_builder = PredicateBuilder.new(self, table) + predicate_builder = PredicateBuilder.new(TableMetadata.new(self, table)) ActiveSupport::Deprecation.warn(<<-EOWARN) sanitize_sql_hash_for_conditions is deprecated, and will be removed in Rails 5.0 EOWARN diff --git a/activerecord/lib/active_record/table_metadata.rb b/activerecord/lib/active_record/table_metadata.rb new file mode 100644 index 0000000000..bf705d3565 --- /dev/null +++ b/activerecord/lib/active_record/table_metadata.rb @@ -0,0 +1,46 @@ +module ActiveRecord + class TableMetadata # :nodoc: + delegate :foreign_type, :foreign_key, to: :association, prefix: true + + def initialize(klass, arel_table, association = nil) + @klass = klass + @arel_table = arel_table + @association = association + end + + def resolve_column_aliases(hash) + hash = hash.dup + hash.keys.grep(Symbol) do |key| + if klass.attribute_alias? key + hash[klass.attribute_alias(key)] = hash.delete key + end + end + hash + end + + def arel_attribute(column_name) + arel_table[column_name] + end + + def associated_with?(association_name) + klass && klass._reflect_on_association(association_name) + end + + def associated_table(table_name) + arel_table = Arel::Table.new(table_name) + association = klass._reflect_on_association(table_name) + if association && !association.polymorphic? + klass = association.klass + end + TableMetadata.new(klass, arel_table, association) + end + + def polymorphic_association? + association && association.polymorphic? + end + + protected + + attr_reader :klass, :arel_table, :association + end +end |