diff options
Diffstat (limited to 'activerecord/lib')
4 files changed, 34 insertions, 52 deletions
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index dd78814c6a..9c4db8a05e 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -33,7 +33,6 @@ module ActiveRecord # This method is a hot spot, so for now, use Hash[] to dup the hash. # https://bugs.ruby-lang.org/issues/7166 @values = Hash[@values] - @values[:bind] = @values[:bind].dup if @values.key? :bind reset end diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 567efce8ae..2860a30f99 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -28,6 +28,27 @@ module ActiveRecord expand_from_hash(attributes) end + def create_binds(attributes) + result = attributes.dup + binds = [] + + attributes.each do |column_name, value| + case value + when String, Integer, ActiveRecord::StatementCache::Substitute + result[column_name] = Arel::Nodes::BindParam.new + binds.push([table.column(column_name), value]) + when Hash + attrs, bvs = associated_predicate_builder(column_name).create_binds(value) + result[column_name] = attrs + binds += bvs + when Relation + binds += value.arel.bind_values + value.bind_values + end + end + + [result, binds] + end + def expand(column, value) # Find the foreign key when using queries such as: # Post.where(author: author) @@ -80,8 +101,7 @@ module ActiveRecord attributes.flat_map do |key, value| if value.is_a?(Hash) - builder = self.class.new(table.associated_table(key)) - builder.expand_from_hash(value) + associated_predicate_builder(key).expand_from_hash(value) else expand(key, value) end @@ -90,6 +110,10 @@ module ActiveRecord private + def associated_predicate_builder(association_name) + self.class.new(table.associated_table(association_name)) + end + def convert_dot_notation_to_hash(attributes) dot_notation = attributes.keys.select { |s| s.include?(".") } diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index d6e6cb4d05..c34e4bfb9b 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -909,7 +909,7 @@ module ActiveRecord end end - bind_values.reject! { |col,_| col.name == target_value } + self.bind_values = bind_values.reject { |col,_| col.name == target_value } end def custom_join_ast(table, joins) @@ -945,11 +945,10 @@ module ActiveRecord when Hash opts = predicate_builder.resolve_column_aliases(opts) - tmp_opts, bind_values = create_binds(opts) + tmp_opts, bind_values = predicate_builder.create_binds(opts) self.bind_values += bind_values attributes = @klass.send(:expand_hash_conditions_for_aggregates, tmp_opts) - add_relations_to_bind_values(attributes) predicate_builder.build_from_hash(attributes) else @@ -957,40 +956,6 @@ module ActiveRecord end end - def create_binds(opts) - bindable, non_binds = opts.partition do |column, value| - case value - when String, Integer, ActiveRecord::StatementCache::Substitute - @klass.columns_hash.include? column.to_s - else - false - end - end - - association_binds, non_binds = non_binds.partition do |column, value| - value.is_a?(Hash) && association_for_table(column) - end - - new_opts = {} - binds = [] - - bindable.each do |(column,value)| - binds.push [@klass.columns_hash[column.to_s], value] - new_opts[column] = connection.substitute_at(column) - end - - association_binds.each do |(column, value)| - association_relation = association_for_table(column).klass.send(:relation) - association_new_opts, association_bind = association_relation.send(:create_binds, value) - new_opts[column] = association_new_opts - binds += association_bind - end - - non_binds.each { |column,value| new_opts[column] = value } - - [new_opts, binds] - end - def association_for_table(table_name) table_name = table_name.to_s @klass._reflect_on_association(table_name) || @@ -1153,17 +1118,5 @@ module ActiveRecord raise ArgumentError, "The method .#{method_name}() must contain arguments." end end - - def add_relations_to_bind_values(attributes) - if attributes.is_a?(Hash) - attributes.each_value do |value| - if value.is_a?(ActiveRecord::Relation) - self.bind_values += value.arel.bind_values + value.bind_values - else - add_relations_to_bind_values(value) - end - end - end - end end end diff --git a/activerecord/lib/active_record/table_metadata.rb b/activerecord/lib/active_record/table_metadata.rb index 11e33e8dfe..31a40adb67 100644 --- a/activerecord/lib/active_record/table_metadata.rb +++ b/activerecord/lib/active_record/table_metadata.rb @@ -22,6 +22,12 @@ module ActiveRecord arel_table[column_name] end + def column(column_name) + if klass + klass.columns_hash[column_name.to_s] + end + end + def associated_with?(association_name) klass && klass._reflect_on_association(association_name) end |