From 10f75af9330c0694a233b856057d0ee453f19e42 Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Fri, 31 Oct 2014 09:43:38 -0600 Subject: Use bind values for joined tables in where statements In practical terms, this allows serialized columns and tz aware columns to be used in wheres that go through joins, where they previously would not behave correctly. Internally, this removes 1/3 of the cases where we rely on Arel to perform type casting for us. There were two non-obvious changes required for this. `update_all` on relation was merging its bind values with arel's in the wrong order. Additionally, through associations were assuming there would be no bind parameters in the preloader (presumably because the where would always be part of a join) [Melanie Gilman & Sean Griffin] --- .../associations/preloader/through_association.rb | 1 + activerecord/lib/active_record/relation.rb | 2 +- .../lib/active_record/relation/query_methods.rb | 17 +++++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) (limited to 'activerecord/lib') diff --git a/activerecord/lib/active_record/associations/preloader/through_association.rb b/activerecord/lib/active_record/associations/preloader/through_association.rb index d57da366bd..12bf3ef138 100644 --- a/activerecord/lib/active_record/associations/preloader/through_association.rb +++ b/activerecord/lib/active_record/associations/preloader/through_association.rb @@ -81,6 +81,7 @@ module ActiveRecord unless reflection_scope.where_values.empty? scope.includes_values = Array(reflection_scope.values[:includes] || options[:source]) scope.where_values = reflection_scope.values[:where] + scope.bind_values = reflection_scope.bind_values end scope.references! reflection_scope.values[:references] diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 7d4a008f44..a25e6e321f 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -336,7 +336,7 @@ module ActiveRecord stmt.wheres = arel.constraints end - bvs = bind_values + arel.bind_values + bvs = arel.bind_values + bind_values @klass.connection.update stmt, 'SQL', bvs end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index d8d416416e..619dfbcc9f 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -980,6 +980,10 @@ module ActiveRecord end end + association_binds, non_binds = non_binds.partition do |column, value| + value.is_a?(Hash) && association_for_table(column) + end + new_opts = {} binds = [] @@ -988,11 +992,24 @@ module ActiveRecord 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) || + @klass._reflect_on_association(table_name.singularize) + end + def build_from opts, name = from_value case opts -- cgit v1.2.3