From 186a1b11449a2b94030791b2c778a76b07bb099f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 22 Dec 2010 17:30:57 -0800 Subject: build an AST rather than build SQL strings --- activerecord/lib/active_record/association_preload.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index f2094283a2..9504b00515 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -185,6 +185,9 @@ module ActiveRecord end def preload_has_and_belongs_to_many_association(records, reflection, preload_options={}) + + left = reflection.klass.arel_table + table_name = reflection.klass.quoted_table_name id_to_record_map, ids = construct_id_map(records) records.each {|record| record.send(reflection.name).loaded} @@ -193,9 +196,15 @@ module ActiveRecord conditions = "t0.#{reflection.primary_key_name} #{in_or_equals_for_ids(ids)}" conditions << append_conditions(reflection, preload_options) + right = Arel::Table.new(options[:join_table]).alias('t0') + condition = left[reflection.klass.primary_key].eq( + right[reflection.association_foreign_key]) + + join = left.create_join(right, left.create_on(condition)) + associated_records_proxy = reflection.klass.unscoped. includes(options[:include]). - joins("INNER JOIN #{connection.quote_table_name options[:join_table]} t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}"). + joins(join). select("#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as the_parent_record_id"). order(options[:order]) -- cgit v1.2.3 From 6ca921a98cefa2bce67486f1ba2a8f52f4170d78 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 22 Dec 2010 18:05:30 -0800 Subject: use arel to compile SQL rather than build strings --- activerecord/lib/active_record/association_preload.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 9504b00515..9ac792fe3f 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -201,11 +201,18 @@ module ActiveRecord right[reflection.association_foreign_key]) join = left.create_join(right, left.create_on(condition)) + select = [ + # FIXME: options[:select] is always nil in the tests. Do we really + # need it? + options[:select] || left[Arel.star], + right[reflection.primary_key_name].as( + Arel.sql('the_parent_record_id')) + ] associated_records_proxy = reflection.klass.unscoped. includes(options[:include]). joins(join). - select("#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as the_parent_record_id"). + select(select). order(options[:order]) all_associated_records = associated_records(ids) do |some_ids| -- cgit v1.2.3 From 3e64336647fefe598ff3b0775401e2c2c5d378d3 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 22 Dec 2010 18:22:54 -0800 Subject: removing SQL interpolation, please use scoping and attribute conditionals as a replacement --- activerecord/lib/active_record/association_preload.rb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 9ac792fe3f..fc7c544a55 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -389,14 +389,9 @@ module ActiveRecord end end - - def interpolate_sql_for_preload(sql) - instance_eval("%@#{sql.gsub('@', '\@')}@", __FILE__, __LINE__) - end - def append_conditions(reflection, preload_options) sql = "" - sql << " AND (#{interpolate_sql_for_preload(reflection.sanitized_conditions)})" if reflection.sanitized_conditions + sql << " AND (#{reflection.sanitized_conditions})" if reflection.sanitized_conditions sql << " AND (#{sanitize_sql preload_options[:conditions]})" if preload_options[:conditions] sql end -- cgit v1.2.3 From 35f5938c9128718a2c5515524c815def75a53f00 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Wed, 22 Dec 2010 18:30:18 -0800 Subject: probably should use the some_ids variable here. o_O --- activerecord/lib/active_record/association_preload.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index fc7c544a55..7f5c5dd2ad 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -216,7 +216,7 @@ module ActiveRecord order(options[:order]) all_associated_records = associated_records(ids) do |some_ids| - associated_records_proxy.where([conditions, ids]).to_a + associated_records_proxy.where([conditions, some_ids]).to_a end set_association_collection_records(id_to_record_map, reflection.name, all_associated_records, 'the_parent_record_id') -- cgit v1.2.3 From df3cfa6aaea326bb60b639524abbcc1f73854d1f Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 23 Dec 2010 07:33:22 -0800 Subject: avoid duping and new objects --- activerecord/lib/active_record/association_preload.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 7f5c5dd2ad..6d905fe6fe 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -211,10 +211,11 @@ module ActiveRecord associated_records_proxy = reflection.klass.unscoped. includes(options[:include]). - joins(join). - select(select). order(options[:order]) + associated_records_proxy.joins_values = [join] + associated_records_proxy.select_values = select + all_associated_records = associated_records(ids) do |some_ids| associated_records_proxy.where([conditions, some_ids]).to_a end -- cgit v1.2.3 From f855090a78b99fc9e1414a1fab21473ef10bc00c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 25 Dec 2010 14:31:22 -0700 Subject: use arel to compile SQL statements --- .../lib/active_record/association_preload.rb | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 6d905fe6fe..7dfb142bb8 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -193,14 +193,15 @@ module ActiveRecord records.each {|record| record.send(reflection.name).loaded} options = reflection.options - conditions = "t0.#{reflection.primary_key_name} #{in_or_equals_for_ids(ids)}" - conditions << append_conditions(reflection, preload_options) - right = Arel::Table.new(options[:join_table]).alias('t0') - condition = left[reflection.klass.primary_key].eq( + + + custom_conditions = append_conditions(reflection, preload_options) + + join_condition = left[reflection.klass.primary_key].eq( right[reflection.association_foreign_key]) - join = left.create_join(right, left.create_on(condition)) + join = left.create_join(right, left.create_on(join_condition)) select = [ # FIXME: options[:select] is always nil in the tests. Do we really # need it? @@ -216,8 +217,16 @@ module ActiveRecord associated_records_proxy.joins_values = [join] associated_records_proxy.select_values = select + method = ids.length > 1 ? 'in' : 'eq' + all_associated_records = associated_records(ids) do |some_ids| - associated_records_proxy.where([conditions, some_ids]).to_a + + conditions = right[reflection.primary_key_name].send( + method, some_ids.length == 1 ? some_ids.first : some_ids + ) + conditions = conditions.and(custom_conditions) unless custom_conditions.empty? + + associated_records_proxy.where(conditions).to_a end set_association_collection_records(id_to_record_map, reflection.name, all_associated_records, 'the_parent_record_id') -- cgit v1.2.3 From 3fe9951fcce97edbc7d1443f165a0b2cb82de1ef Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 25 Dec 2010 14:34:13 -0700 Subject: refactoring AST building --- activerecord/lib/active_record/association_preload.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 7dfb142bb8..9c79e6225a 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -217,13 +217,11 @@ module ActiveRecord associated_records_proxy.joins_values = [join] associated_records_proxy.select_values = select - method = ids.length > 1 ? 'in' : 'eq' - all_associated_records = associated_records(ids) do |some_ids| + method = some_ids.length == 1 ? ['eq', some_ids.first] : + ['in', some_ids] - conditions = right[reflection.primary_key_name].send( - method, some_ids.length == 1 ? some_ids.first : some_ids - ) + conditions = right[reflection.primary_key_name].send(*method) conditions = conditions.and(custom_conditions) unless custom_conditions.empty? associated_records_proxy.where(conditions).to_a -- cgit v1.2.3 From a6fe244e9b05c60aac88842a38fb2b6285d5571b Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 25 Dec 2010 15:23:45 -0700 Subject: take more advantage of arel sql compiler --- .../lib/active_record/association_preload.rb | 32 ++++++++++++++-------- 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 9c79e6225a..11c2084b5b 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -196,8 +196,6 @@ module ActiveRecord right = Arel::Table.new(options[:join_table]).alias('t0') - custom_conditions = append_conditions(reflection, preload_options) - join_condition = left[reflection.klass.primary_key].eq( right[reflection.association_foreign_key]) @@ -217,12 +215,16 @@ module ActiveRecord associated_records_proxy.joins_values = [join] associated_records_proxy.select_values = select + custom_conditions = append_conditions(reflection, preload_options) + all_associated_records = associated_records(ids) do |some_ids| method = some_ids.length == 1 ? ['eq', some_ids.first] : ['in', some_ids] conditions = right[reflection.primary_key_name].send(*method) - conditions = conditions.and(custom_conditions) unless custom_conditions.empty? + conditions = custom_conditions.inject(conditions) do |ast, cond| + ast.and cond + end associated_records_proxy.where(conditions).to_a end @@ -348,7 +350,7 @@ module ActiveRecord klasses_and_ids.each do |klass_name, _id_map| klass = klass_name.constantize - table_name = klass.quoted_table_name + table = klass.arel_table primary_key = (reflection.options[:primary_key] || klass.primary_key).to_s column_type = klass.columns.detect{|c| c.name == primary_key}.type @@ -362,10 +364,15 @@ module ActiveRecord end end - conditions = "#{table_name}.#{connection.quote_column_name(primary_key)} #{in_or_equals_for_ids(ids)}" - conditions << append_conditions(reflection, preload_options) + method = ids.length == 1 ? ['eq', ids.first] : ['in', ids] + conditions = table[primary_key].send(*method) + + custom_conditions = append_conditions(reflection, preload_options) + conditions = custom_conditions.inject(conditions) do |ast, cond| + ast.and cond + end - associated_records = klass.unscoped.where([conditions, ids]).apply_finder_options(options.slice(:include, :select, :joins, :order)).to_a + associated_records = klass.unscoped.where(conditions).apply_finder_options(options.slice(:include, :select, :joins, :order)).to_a set_association_single_records(_id_map, reflection.name, associated_records, primary_key) end @@ -382,7 +389,8 @@ module ActiveRecord conditions = "#{reflection.klass.quoted_table_name}.#{foreign_key} #{in_or_equals_for_ids(ids)}" end - conditions << append_conditions(reflection, preload_options) + conditions = ([conditions] + + append_conditions(reflection, preload_options)).join(' AND ') find_options = { :select => preload_options[:select] || options[:select] || Arel::SqlLiteral.new("#{table_name}.*"), @@ -398,10 +406,10 @@ module ActiveRecord end def append_conditions(reflection, preload_options) - sql = "" - sql << " AND (#{reflection.sanitized_conditions})" if reflection.sanitized_conditions - sql << " AND (#{sanitize_sql preload_options[:conditions]})" if preload_options[:conditions] - sql + [ + ("(#{reflection.sanitized_conditions})" if reflection.sanitized_conditions), + ("(#{sanitize_sql preload_options[:conditions]})" if preload_options[:conditions]), + ].compact.map { |x| Arel.sql x } end def in_or_equals_for_ids(ids) -- cgit v1.2.3 From 0a609eea504f72baead7548d47f0fe707314a033 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 25 Dec 2010 15:25:11 -0700 Subject: use sql literal factory method --- activerecord/lib/active_record/association_preload.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 11c2084b5b..83383e9b19 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -393,7 +393,7 @@ module ActiveRecord append_conditions(reflection, preload_options)).join(' AND ') find_options = { - :select => preload_options[:select] || options[:select] || Arel::SqlLiteral.new("#{table_name}.*"), + :select => preload_options[:select] || options[:select] || Arel.sql("#{table_name}.*"), :include => preload_options[:include] || options[:include], :joins => options[:joins], :group => preload_options[:group] || options[:group], -- cgit v1.2.3 From 5b918bb97cb1801945ef778508a3738da98012c5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 25 Dec 2010 16:19:59 -0700 Subject: using arel to compile sql statements --- .../lib/active_record/association_preload.rb | 25 +++++++++++++++------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 83383e9b19..7b4ff69b87 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -379,18 +379,20 @@ module ActiveRecord end def find_associated_records(ids, reflection, preload_options) - options = reflection.options + options = reflection.options + table = reflection.klass.arel_table table_name = reflection.klass.quoted_table_name + conditions = [] + + key = reflection.primary_key_name + if interface = reflection.options[:as] - conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} #{in_or_equals_for_ids(ids)} and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{self.base_class.sti_name}'" - else - foreign_key = reflection.primary_key_name - conditions = "#{reflection.klass.quoted_table_name}.#{foreign_key} #{in_or_equals_for_ids(ids)}" + key = "#{interface}_id" + conditions << table["#{interface}_type"].eq(base_class.sti_name) end - conditions = ([conditions] + - append_conditions(reflection, preload_options)).join(' AND ') + conditions += append_conditions(reflection, preload_options) find_options = { :select => preload_options[:select] || options[:select] || Arel.sql("#{table_name}.*"), @@ -401,7 +403,14 @@ module ActiveRecord } associated_records(ids) do |some_ids| - reflection.klass.scoped.apply_finder_options(find_options.merge(:conditions => [conditions, some_ids])).to_a + method = some_ids.length == 1 ? ['eq', some_ids.first] : + ['in', some_ids] + + where = conditions.inject(table[key].send(*method)) do |ast, cond| + ast.and cond + end + + reflection.klass.scoped.apply_finder_options(find_options.merge(:conditions => where)).to_a end end -- cgit v1.2.3 From 33b5a2637fbed8b2e5a10b84b79b32245edfb411 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 25 Dec 2010 16:36:07 -0700 Subject: refactoring method selection --- activerecord/lib/active_record/association_preload.rb | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 7b4ff69b87..5feda5db0c 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -188,7 +188,6 @@ module ActiveRecord left = reflection.klass.arel_table - table_name = reflection.klass.quoted_table_name id_to_record_map, ids = construct_id_map(records) records.each {|record| record.send(reflection.name).loaded} options = reflection.options @@ -218,9 +217,7 @@ module ActiveRecord custom_conditions = append_conditions(reflection, preload_options) all_associated_records = associated_records(ids) do |some_ids| - method = some_ids.length == 1 ? ['eq', some_ids.first] : - ['in', some_ids] - + method = in_or_equal(some_ids) conditions = right[reflection.primary_key_name].send(*method) conditions = custom_conditions.inject(conditions) do |ast, cond| ast.and cond @@ -364,7 +361,7 @@ module ActiveRecord end end - method = ids.length == 1 ? ['eq', ids.first] : ['in', ids] + method = in_or_equal(ids) conditions = table[primary_key].send(*method) custom_conditions = append_conditions(reflection, preload_options) @@ -403,9 +400,7 @@ module ActiveRecord } associated_records(ids) do |some_ids| - method = some_ids.length == 1 ? ['eq', some_ids.first] : - ['in', some_ids] - + method = in_or_equal(some_ids) where = conditions.inject(table[key].send(*method)) do |ast, cond| ast.and cond end @@ -421,8 +416,8 @@ module ActiveRecord ].compact.map { |x| Arel.sql x } end - def in_or_equals_for_ids(ids) - ids.size > 1 ? "IN (?)" : "= ?" + def in_or_equal(ids) + ids.length == 1 ? ['eq', ids.first] : ['in', ids] end # Some databases impose a limit on the number of ids in a list (in Oracle its 1000) -- cgit v1.2.3 From 75ac9c4271df65b94b2a6862d87b1ec42f676efe Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 25 Dec 2010 16:38:59 -0700 Subject: use arel to determine selection column --- activerecord/lib/active_record/association_preload.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 5feda5db0c..3409ca9099 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -378,7 +378,6 @@ module ActiveRecord def find_associated_records(ids, reflection, preload_options) options = reflection.options table = reflection.klass.arel_table - table_name = reflection.klass.quoted_table_name conditions = [] @@ -392,7 +391,7 @@ module ActiveRecord conditions += append_conditions(reflection, preload_options) find_options = { - :select => preload_options[:select] || options[:select] || Arel.sql("#{table_name}.*"), + :select => preload_options[:select] || options[:select] || table[Arel.star], :include => preload_options[:include] || options[:include], :joins => options[:joins], :group => preload_options[:group] || options[:group], -- cgit v1.2.3 From bde643fbec7d1b80309d3387635f4a2e9dadccc2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 25 Dec 2010 16:42:49 -0700 Subject: arel will deal with casting the ids, so we can delete this --- activerecord/lib/active_record/association_preload.rb | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 3409ca9099..a305551093 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -349,19 +349,7 @@ module ActiveRecord table = klass.arel_table primary_key = (reflection.options[:primary_key] || klass.primary_key).to_s - column_type = klass.columns.detect{|c| c.name == primary_key}.type - - ids = _id_map.keys.map do |id| - if column_type == :integer - id.to_i - elsif column_type == :float - id.to_f - else - id - end - end - - method = in_or_equal(ids) + method = in_or_equal(_id_map.keys) conditions = table[primary_key].send(*method) custom_conditions = append_conditions(reflection, preload_options) -- cgit v1.2.3 From d767252d72063af053fdf1391461704a1a5e1f4a Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 25 Dec 2010 16:47:59 -0700 Subject: refactor to use group_by --- activerecord/lib/active_record/association_preload.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index a305551093..ba225b700c 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -336,11 +336,11 @@ module ActiveRecord end end else - id_map = {} - records.each do |record| + id_map = records.group_by do |record| key = record.send(primary_key_name) - (id_map[key.to_s] ||= []) << record if key + key && key.to_s end + id_map.delete nil klasses_and_ids[reflection.klass.name] = id_map unless id_map.empty? end -- cgit v1.2.3 From 9f5c18ce075179cfc73a00cba9a19d69aaf5274c Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sun, 26 Dec 2010 21:37:25 +0000 Subject: Refactor we_can_set_the_inverse_on_this? to use a less bizarre name amongst other things --- activerecord/lib/active_record/association_preload.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index ba225b700c..94bcc869c2 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -127,8 +127,7 @@ module ActiveRecord association_proxy = parent_record.send(reflection_name) association_proxy.loaded association_proxy.target.push(*Array.wrap(associated_record)) - - association_proxy.__send__(:set_inverse_instance, associated_record, parent_record) + association_proxy.send(:set_inverse_instance, associated_record) end end @@ -157,7 +156,7 @@ module ActiveRecord mapped_records = id_to_record_map[associated_record[key].to_s] mapped_records.each do |mapped_record| association_proxy = mapped_record.send("set_#{reflection_name}_target", associated_record) - association_proxy.__send__(:set_inverse_instance, associated_record, mapped_record) + association_proxy.send(:set_inverse_instance, associated_record) end end -- cgit v1.2.3 From 67da59097909295c59574e3fd3b502022f860aea Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 26 Dec 2010 20:15:09 -0700 Subject: make our hash of klasses and ids actually have classes for keys --- activerecord/lib/active_record/association_preload.rb | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 94bcc869c2..b39b703a92 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -329,7 +329,7 @@ module ActiveRecord if klass = record.send(polymorph_type) klass_id = record.send(primary_key_name) if klass_id - id_map = klasses_and_ids[klass] ||= {} + id_map = klasses_and_ids[klass.constantize] ||= {} (id_map[klass_id.to_s] ||= []) << record end end @@ -340,16 +340,14 @@ module ActiveRecord key && key.to_s end id_map.delete nil - klasses_and_ids[reflection.klass.name] = id_map unless id_map.empty? + klasses_and_ids[reflection.klass] = id_map unless id_map.empty? end - klasses_and_ids.each do |klass_name, _id_map| - klass = klass_name.constantize - - table = klass.arel_table + klasses_and_ids.each do |klass, _id_map| + table = klass.arel_table primary_key = (reflection.options[:primary_key] || klass.primary_key).to_s - method = in_or_equal(_id_map.keys) - conditions = table[primary_key].send(*method) + method = in_or_equal(_id_map.keys) + conditions = table[primary_key].send(*method) custom_conditions = append_conditions(reflection, preload_options) conditions = custom_conditions.inject(conditions) do |ast, cond| -- cgit v1.2.3 From 9bac649fa4ca6f05795e7cab8d30049aa2410cb8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sun, 26 Dec 2010 20:22:13 -0700 Subject: try not to make so many funcalls --- activerecord/lib/active_record/association_preload.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index b39b703a92..ecf7b6c210 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -147,13 +147,16 @@ module ActiveRecord def set_association_single_records(id_to_record_map, reflection_name, associated_records, key) seen_keys = {} associated_records.each do |associated_record| + seen_key = associated_record[key].to_s + #this is a has_one or belongs_to: there should only be one record. #Unfortunately we can't (in portable way) ask the database for #'all records where foo_id in (x,y,z), but please # only one row per distinct foo_id' so this where we enforce that - next if seen_keys[associated_record[key].to_s] - seen_keys[associated_record[key].to_s] = true - mapped_records = id_to_record_map[associated_record[key].to_s] + next if seen_keys.key? seen_key + + seen_keys[seen_key] = true + mapped_records = id_to_record_map[seen_key] mapped_records.each do |mapped_record| association_proxy = mapped_record.send("set_#{reflection_name}_target", associated_record) association_proxy.send(:set_inverse_instance, associated_record) -- cgit v1.2.3 From 12675988813e82ac30f7c0e0008c12c4cf5d8cdc Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 31 Dec 2010 20:00:24 +0000 Subject: Rename AssociationReflection#primary_key_name to foreign_key, since the options key which it relates to is :foreign_key --- .../lib/active_record/association_preload.rb | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index ecf7b6c210..638897a86b 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -205,7 +205,7 @@ module ActiveRecord # FIXME: options[:select] is always nil in the tests. Do we really # need it? options[:select] || left[Arel.star], - right[reflection.primary_key_name].as( + right[reflection.foreign_key].as( Arel.sql('the_parent_record_id')) ] @@ -220,7 +220,7 @@ module ActiveRecord all_associated_records = associated_records(ids) do |some_ids| method = in_or_equal(some_ids) - conditions = right[reflection.primary_key_name].send(*method) + conditions = right[reflection.foreign_key].send(*method) conditions = custom_conditions.inject(conditions) do |ast, cond| ast.and cond end @@ -241,7 +241,7 @@ module ActiveRecord unless through_records.empty? through_reflection = reflections[options[:through]] - through_primary_key = through_reflection.primary_key_name + through_primary_key = through_reflection.foreign_key source = reflection.source_reflection.name through_records.first.class.preload_associations(through_records, source) if through_reflection.macro == :belongs_to @@ -255,7 +255,7 @@ module ActiveRecord end end else - set_association_single_records(id_to_record_map, reflection.name, find_associated_records(ids, reflection, preload_options), reflection.primary_key_name) + set_association_single_records(id_to_record_map, reflection.name, find_associated_records(ids, reflection, preload_options), reflection.foreign_key) end end @@ -263,8 +263,8 @@ module ActiveRecord return if records.first.send(reflection.name).loaded? options = reflection.options - primary_key_name = reflection.through_reflection_primary_key_name - id_to_record_map, ids = construct_id_map(records, primary_key_name || reflection.options[:primary_key]) + foreign_key = reflection.through_reflection_foreign_key + id_to_record_map, ids = construct_id_map(records, foreign_key || reflection.options[:primary_key]) records.each {|record| record.send(reflection.name).loaded} if options[:through] @@ -281,7 +281,7 @@ module ActiveRecord else set_association_collection_records(id_to_record_map, reflection.name, find_associated_records(ids, reflection, preload_options), - reflection.primary_key_name) + reflection.foreign_key) end end @@ -319,7 +319,7 @@ module ActiveRecord def preload_belongs_to_association(records, reflection, preload_options={}) return if records.first.send("loaded_#{reflection.name}?") options = reflection.options - primary_key_name = reflection.primary_key_name + foreign_key = reflection.foreign_key klasses_and_ids = {} @@ -330,7 +330,7 @@ module ActiveRecord # to their parent_records records.each do |record| if klass = record.send(polymorph_type) - klass_id = record.send(primary_key_name) + klass_id = record.send(foreign_key) if klass_id id_map = klasses_and_ids[klass.constantize] ||= {} (id_map[klass_id.to_s] ||= []) << record @@ -339,7 +339,7 @@ module ActiveRecord end else id_map = records.group_by do |record| - key = record.send(primary_key_name) + key = record.send(foreign_key) key && key.to_s end id_map.delete nil @@ -369,7 +369,7 @@ module ActiveRecord conditions = [] - key = reflection.primary_key_name + key = reflection.foreign_key if interface = reflection.options[:as] key = "#{interface}_id" -- cgit v1.2.3 From c47f802d0e7b0156512f197887d6e9bda6d0f269 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sat, 1 Jan 2011 18:52:48 +0000 Subject: Have a proper AssociationReflection#foreign_type method rather than using options[:foreign_type] --- activerecord/lib/active_record/association_preload.rb | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 638897a86b..e3aee701a8 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -287,7 +287,7 @@ module ActiveRecord def preload_through_records(records, reflection, through_association) if reflection.options[:source_type] - interface = reflection.source_reflection.options[:foreign_type] + interface = reflection.source_reflection.foreign_type preload_options = {:conditions => ["#{connection.quote_column_name interface} = ?", reflection.options[:source_type]]} records.compact! @@ -319,18 +319,15 @@ module ActiveRecord def preload_belongs_to_association(records, reflection, preload_options={}) return if records.first.send("loaded_#{reflection.name}?") options = reflection.options - foreign_key = reflection.foreign_key klasses_and_ids = {} if options[:polymorphic] - polymorph_type = options[:foreign_type] - # Construct a mapping from klass to a list of ids to load and a mapping of those ids back # to their parent_records records.each do |record| - if klass = record.send(polymorph_type) - klass_id = record.send(foreign_key) + if klass = record.send(reflection.foreign_type) + klass_id = record.send(reflection.foreign_key) if klass_id id_map = klasses_and_ids[klass.constantize] ||= {} (id_map[klass_id.to_s] ||= []) << record @@ -339,7 +336,7 @@ module ActiveRecord end else id_map = records.group_by do |record| - key = record.send(foreign_key) + key = record.send(reflection.foreign_key) key && key.to_s end id_map.delete nil -- cgit v1.2.3 From a9bed985cfd7d1ae93f475542bb878aa939e1c1e Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 3 Jan 2011 13:38:40 +0000 Subject: When preloading a belongs_to, the target should still be set (to nil) if there is no foreign key present. And the loaded flag should be set on the association proxy. This then allows us to remove the foreign_key_present? check from BelongsToAssociation#find_target. Also added a test for the same thing on polymorphic associations. --- .../lib/active_record/association_preload.rb | 23 +++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index e3aee701a8..5aad2b4558 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -339,22 +339,27 @@ module ActiveRecord key = record.send(reflection.foreign_key) key && key.to_s end - id_map.delete nil klasses_and_ids[reflection.klass] = id_map unless id_map.empty? end klasses_and_ids.each do |klass, _id_map| - table = klass.arel_table primary_key = (reflection.options[:primary_key] || klass.primary_key).to_s - method = in_or_equal(_id_map.keys) - conditions = table[primary_key].send(*method) + keys = _id_map.keys.compact - custom_conditions = append_conditions(reflection, preload_options) - conditions = custom_conditions.inject(conditions) do |ast, cond| - ast.and cond - end + unless keys.empty? + table = klass.arel_table + method = in_or_equal(keys) + conditions = table[primary_key].send(*method) - associated_records = klass.unscoped.where(conditions).apply_finder_options(options.slice(:include, :select, :joins, :order)).to_a + custom_conditions = append_conditions(reflection, preload_options) + conditions = custom_conditions.inject(conditions) do |ast, cond| + ast.and cond + end + + associated_records = klass.unscoped.where(conditions).apply_finder_options(options.slice(:include, :select, :joins, :order)).to_a + else + associated_records = [] + end set_association_single_records(_id_map, reflection.name, associated_records, primary_key) end -- cgit v1.2.3 From a60ea742226f09dc566ad5d9a0b465c5d5db9687 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Mon, 10 Jan 2011 17:30:40 -0800 Subject: only use one array when collecting split up queries --- activerecord/lib/active_record/association_preload.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 5aad2b4558..dc15b2f4c3 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -415,7 +415,7 @@ module ActiveRecord in_clause_length = connection.in_clause_length || ids.size records = [] ids.each_slice(in_clause_length) do |some_ids| - records += yield(some_ids) + records.concat yield(some_ids) end records end -- cgit v1.2.3 From f6b71dea15435ea91e4db27ddf657ff840fd3a72 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 11 Jan 2011 13:38:17 -0800 Subject: avoid splatting arrays by using concat --- activerecord/lib/active_record/association_preload.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index dc15b2f4c3..bb7ddfcae9 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -126,7 +126,7 @@ module ActiveRecord parent_records.each do |parent_record| association_proxy = parent_record.send(reflection_name) association_proxy.loaded - association_proxy.target.push(*Array.wrap(associated_record)) + association_proxy.target.concat(Array.wrap(associated_record)) association_proxy.send(:set_inverse_instance, associated_record) end end @@ -139,8 +139,8 @@ module ActiveRecord def set_association_collection_records(id_to_record_map, reflection_name, associated_records, key) associated_records.each do |associated_record| - mapped_records = id_to_record_map[associated_record[key].to_s] - add_preloaded_records_to_collection(mapped_records, reflection_name, associated_record) + parent_records = id_to_record_map[associated_record[key].to_s] + add_preloaded_records_to_collection(parent_records, reflection_name, associated_record) end end -- cgit v1.2.3 From 681ab53ba15f9fc95c8a91e50bb0138aa66967b2 Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Sun, 9 Jan 2011 18:37:01 +0000 Subject: Get rid of set_association_target and association_loaded? as the parts of the code that need that can now just use association_proxy(:name).loaded?/target= --- activerecord/lib/active_record/association_preload.rb | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index bb7ddfcae9..4c517e3339 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -133,7 +133,7 @@ module ActiveRecord def add_preloaded_record_to_collection(parent_records, reflection_name, associated_record) parent_records.each do |parent_record| - parent_record.send("set_#{reflection_name}_target", associated_record) + parent_record.send(:association_proxy, reflection_name).target = associated_record end end @@ -158,14 +158,17 @@ module ActiveRecord seen_keys[seen_key] = true mapped_records = id_to_record_map[seen_key] mapped_records.each do |mapped_record| - association_proxy = mapped_record.send("set_#{reflection_name}_target", associated_record) + association_proxy = mapped_record.send(:association_proxy, reflection_name) + association_proxy.target = associated_record association_proxy.send(:set_inverse_instance, associated_record) end end id_to_record_map.each do |id, records| next if seen_keys.include?(id.to_s) - records.each {|record| record.send("set_#{reflection_name}_target", nil) } + records.each do |record| + record.send(:association_proxy, reflection_name).target = nil + end end end @@ -232,10 +235,14 @@ module ActiveRecord end def preload_has_one_association(records, reflection, preload_options={}) - return if records.first.send("loaded_#{reflection.name}?") + return if records.first.send(:association_proxy, reflection.name).loaded? id_to_record_map, ids = construct_id_map(records, reflection.options[:primary_key]) options = reflection.options - records.each {|record| record.send("set_#{reflection.name}_target", nil)} + + records.each do |record| + record.send(:association_proxy, reflection.name).target = nil + end + if options[:through] through_records = preload_through_records(records, reflection, options[:through]) @@ -317,7 +324,7 @@ module ActiveRecord end def preload_belongs_to_association(records, reflection, preload_options={}) - return if records.first.send("loaded_#{reflection.name}?") + return if records.first.send(:association_proxy, reflection.name).loaded? options = reflection.options klasses_and_ids = {} -- cgit v1.2.3 From 8c71e8b18f0e589b5413a8e6b6d7336a5506c977 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 11 Jan 2011 15:16:09 -0800 Subject: lazily instantiate AR objects in order to avoid NoMethodErrors --- .../lib/active_record/association_preload.rb | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 4c517e3339..68aaff175a 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -137,9 +137,9 @@ module ActiveRecord end end - def set_association_collection_records(id_to_record_map, reflection_name, associated_records, key) + def set_association_collection_records(id_to_parent_map, reflection_name, associated_records, key) associated_records.each do |associated_record| - parent_records = id_to_record_map[associated_record[key].to_s] + parent_records = id_to_parent_map[associated_record[key].to_s] add_preloaded_records_to_collection(parent_records, reflection_name, associated_record) end end @@ -199,7 +199,6 @@ module ActiveRecord right = Arel::Table.new(options[:join_table]).alias('t0') - join_condition = left[reflection.klass.primary_key].eq( right[reflection.association_foreign_key]) @@ -221,17 +220,24 @@ module ActiveRecord custom_conditions = append_conditions(reflection, preload_options) - all_associated_records = associated_records(ids) do |some_ids| + klass = associated_records_proxy.klass + + associated_records(ids) { |some_ids| method = in_or_equal(some_ids) conditions = right[reflection.foreign_key].send(*method) conditions = custom_conditions.inject(conditions) do |ast, cond| ast.and cond end - associated_records_proxy.where(conditions).to_a - end - - set_association_collection_records(id_to_record_map, reflection.name, all_associated_records, 'the_parent_record_id') + relation = associated_records_proxy.where(conditions) + klass.connection.select_all(relation.arel.to_sql, 'SQL', relation.bind_values) + }.map! { |row| + parent_records = id_to_record_map[row['the_parent_record_id'].to_s] + associated_record = klass.instantiate row + add_preloaded_records_to_collection( + parent_records, reflection.name, associated_record) + associated_record + } end def preload_has_one_association(records, reflection, preload_options={}) -- cgit v1.2.3 From 4bc9bacd9458af9f9ad3a5075de6425e3c1c6a1e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 18 Jan 2011 15:05:18 -0800 Subject: refactor elaborate group_by in to a normal group_by --- activerecord/lib/active_record/association_preload.rb | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 68aaff175a..4b90845244 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -177,16 +177,11 @@ module ActiveRecord # (id_to_record_map, ids) where +id_to_record_map+ is the Hash, # and +ids+ is an Array of record IDs. def construct_id_map(records, primary_key=nil) - id_to_record_map = {} - ids = [] - records.each do |record| + id_to_record_map = records.group_by do |record| primary_key ||= record.class.primary_key - ids << record[primary_key] - mapped_records = (id_to_record_map[ids.last.to_s] ||= []) - mapped_records << record + record[primary_key].to_s end - ids.uniq! - return id_to_record_map, ids + return id_to_record_map, id_to_record_map.keys end def preload_has_and_belongs_to_many_association(records, reflection, preload_options={}) -- cgit v1.2.3 From ba62a87b8b3ab2cffb6e8af6c110ec17b9c0bab2 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 18 Jan 2011 15:15:20 -0800 Subject: ony bother with record map keys when we need them --- activerecord/lib/active_record/association_preload.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 4b90845244..d89f87dbc7 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -177,18 +177,18 @@ module ActiveRecord # (id_to_record_map, ids) where +id_to_record_map+ is the Hash, # and +ids+ is an Array of record IDs. def construct_id_map(records, primary_key=nil) - id_to_record_map = records.group_by do |record| + records.group_by do |record| primary_key ||= record.class.primary_key record[primary_key].to_s end - return id_to_record_map, id_to_record_map.keys end def preload_has_and_belongs_to_many_association(records, reflection, preload_options={}) left = reflection.klass.arel_table - id_to_record_map, ids = construct_id_map(records) + id_to_record_map = construct_id_map(records) + records.each {|record| record.send(reflection.name).loaded} options = reflection.options @@ -217,7 +217,7 @@ module ActiveRecord klass = associated_records_proxy.klass - associated_records(ids) { |some_ids| + associated_records(id_to_record_map.keys) { |some_ids| method = in_or_equal(some_ids) conditions = right[reflection.foreign_key].send(*method) conditions = custom_conditions.inject(conditions) do |ast, cond| @@ -237,7 +237,7 @@ module ActiveRecord def preload_has_one_association(records, reflection, preload_options={}) return if records.first.send(:association_proxy, reflection.name).loaded? - id_to_record_map, ids = construct_id_map(records, reflection.options[:primary_key]) + id_to_record_map = construct_id_map(records, reflection.options[:primary_key]) options = reflection.options records.each do |record| @@ -253,7 +253,7 @@ module ActiveRecord source = reflection.source_reflection.name through_records.first.class.preload_associations(through_records, source) if through_reflection.macro == :belongs_to - id_to_record_map = construct_id_map(records, through_primary_key).first + id_to_record_map = construct_id_map(records, through_primary_key) through_primary_key = through_reflection.klass.primary_key end @@ -263,7 +263,7 @@ module ActiveRecord end end else - set_association_single_records(id_to_record_map, reflection.name, find_associated_records(ids, reflection, preload_options), reflection.foreign_key) + set_association_single_records(id_to_record_map, reflection.name, find_associated_records(id_to_record_map.keys, reflection, preload_options), reflection.foreign_key) end end @@ -272,7 +272,7 @@ module ActiveRecord options = reflection.options foreign_key = reflection.through_reflection_foreign_key - id_to_record_map, ids = construct_id_map(records, foreign_key || reflection.options[:primary_key]) + id_to_record_map = construct_id_map(records, foreign_key || reflection.options[:primary_key]) records.each {|record| record.send(reflection.name).loaded} if options[:through] @@ -288,7 +288,7 @@ module ActiveRecord end else - set_association_collection_records(id_to_record_map, reflection.name, find_associated_records(ids, reflection, preload_options), + set_association_collection_records(id_to_record_map, reflection.name, find_associated_records(id_to_record_map.keys, reflection, preload_options), reflection.foreign_key) end end -- cgit v1.2.3 From 9e42f1b416771ba91455de711ae680b55640377e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 18 Jan 2011 15:19:41 -0800 Subject: reduce method calls and loops when dealing with custom conditions --- activerecord/lib/active_record/association_preload.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index d89f87dbc7..74e957f828 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -219,10 +219,9 @@ module ActiveRecord associated_records(id_to_record_map.keys) { |some_ids| method = in_or_equal(some_ids) - conditions = right[reflection.foreign_key].send(*method) - conditions = custom_conditions.inject(conditions) do |ast, cond| - ast.and cond - end + conditions = right.create_and( + [right[reflection.foreign_key].send(*method)] + + custom_conditions) relation = associated_records_proxy.where(conditions) klass.connection.select_all(relation.arel.to_sql, 'SQL', relation.bind_values) -- cgit v1.2.3 From f3a5995bbf7a46f5b94e830f97908a3a9314d46e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 18 Jan 2011 15:21:14 -0800 Subject: keys will always be strings in the id => record map --- activerecord/lib/active_record/association_preload.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 74e957f828..3fb3642125 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -165,7 +165,7 @@ module ActiveRecord end id_to_record_map.each do |id, records| - next if seen_keys.include?(id.to_s) + next if seen_keys.include?(id) records.each do |record| record.send(:association_proxy, reflection_name).target = nil end -- cgit v1.2.3 From c107849a997f1014d2e28ce394c3d9ccb3a1f50c Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 18 Jan 2011 15:33:19 -0800 Subject: reduce objects, reduce loops and function calls while building the conditional --- activerecord/lib/active_record/association_preload.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 3fb3642125..8e71c6eec5 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -385,7 +385,7 @@ module ActiveRecord conditions << table["#{interface}_type"].eq(base_class.sti_name) end - conditions += append_conditions(reflection, preload_options) + conditions.concat append_conditions(reflection, preload_options) find_options = { :select => preload_options[:select] || options[:select] || table[Arel.star], @@ -397,9 +397,7 @@ module ActiveRecord associated_records(ids) do |some_ids| method = in_or_equal(some_ids) - where = conditions.inject(table[key].send(*method)) do |ast, cond| - ast.and cond - end + where = table.create_and(conditions + [table[key].send(*method)]) reflection.klass.scoped.apply_finder_options(find_options.merge(:conditions => where)).to_a end -- cgit v1.2.3 From a282301a77288252d135855d088f20de2397998e Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Tue, 18 Jan 2011 16:33:18 -0800 Subject: we have a method for setting preloaded records, so use it --- activerecord/lib/active_record/association_preload.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index 8e71c6eec5..cba4bab3ef 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -166,9 +166,7 @@ module ActiveRecord id_to_record_map.each do |id, records| next if seen_keys.include?(id) - records.each do |record| - record.send(:association_proxy, reflection_name).target = nil - end + add_preloaded_record_to_collection(records, reflection_name, nil) end end @@ -239,9 +237,7 @@ module ActiveRecord id_to_record_map = construct_id_map(records, reflection.options[:primary_key]) options = reflection.options - records.each do |record| - record.send(:association_proxy, reflection.name).target = nil - end + add_preloaded_record_to_collection(records, reflection.name, nil) if options[:through] through_records = preload_through_records(records, reflection, options[:through]) -- cgit v1.2.3 From aa86420be24d7df9c07379bcf6f33904d0d41adc Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Mon, 24 Jan 2011 20:57:11 +0000 Subject: Rename AssociationProxy#loaded to loaded! as it mutates the association --- activerecord/lib/active_record/association_preload.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index cba4bab3ef..b83c00e9f8 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -125,7 +125,7 @@ module ActiveRecord def add_preloaded_records_to_collection(parent_records, reflection_name, associated_record) parent_records.each do |parent_record| association_proxy = parent_record.send(reflection_name) - association_proxy.loaded + association_proxy.loaded! association_proxy.target.concat(Array.wrap(associated_record)) association_proxy.send(:set_inverse_instance, associated_record) end @@ -187,7 +187,7 @@ module ActiveRecord id_to_record_map = construct_id_map(records) - records.each {|record| record.send(reflection.name).loaded} + records.each { |record| record.send(reflection.name).loaded! } options = reflection.options right = Arel::Table.new(options[:join_table]).alias('t0') @@ -268,7 +268,7 @@ module ActiveRecord foreign_key = reflection.through_reflection_foreign_key id_to_record_map = construct_id_map(records, foreign_key || reflection.options[:primary_key]) - records.each {|record| record.send(reflection.name).loaded} + records.each { |record| record.send(reflection.name).loaded! } if options[:through] through_records = preload_through_records(records, reflection, options[:through]) -- cgit v1.2.3 From a7e19b30ca71f62af516675023659be061b2b70a Mon Sep 17 00:00:00 2001 From: Jon Leighton Date: Fri, 11 Feb 2011 22:22:19 +0000 Subject: Add interpolation of association conditions back in, in the form of proc { ... } rather than instance_eval-ing strings --- activerecord/lib/active_record/association_preload.rb | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'activerecord/lib/active_record/association_preload.rb') diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb index b83c00e9f8..52d2c49836 100644 --- a/activerecord/lib/active_record/association_preload.rb +++ b/activerecord/lib/active_record/association_preload.rb @@ -399,10 +399,18 @@ module ActiveRecord end end + def process_conditions(conditions, klass = self) + if conditions.respond_to?(:to_proc) + conditions = instance_eval(&conditions) + end + + klass.send(:sanitize_sql, conditions) + end + def append_conditions(reflection, preload_options) [ - ("(#{reflection.sanitized_conditions})" if reflection.sanitized_conditions), - ("(#{sanitize_sql preload_options[:conditions]})" if preload_options[:conditions]), + ('(' + process_conditions(reflection.options[:conditions], reflection.klass) + ')' if reflection.options[:conditions]), + ('(' + process_conditions(preload_options[:conditions]) + ')' if preload_options[:conditions]), ].compact.map { |x| Arel.sql x } end -- cgit v1.2.3