diff options
Diffstat (limited to 'activerecord')
5 files changed, 0 insertions, 199 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 028157d7e9..44d3258c40 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -39,14 +39,6 @@ module ActiveRecord end end - class HasManyThroughSourceAssociationMacroError < ActiveRecordError #:nodoc: - def initialize(reflection) - through_reflection = reflection.through_reflection - source_reflection = reflection.source_reflection - super("Invalid source reflection macro :#{source_reflection.macro}#{" :through" if source_reflection.options[:through]} for has_many #{reflection.name.inspect}, :through => #{through_reflection.name.inspect}. Use :source to specify the source reflection.") - end - end - class HasManyThroughCantAssociateThroughHasOneOrManyReflection < ActiveRecordError #:nodoc: def initialize(owner, reflection) super("Cannot modify association '#{owner.class.name}##{reflection.name}' because the source reflection class '#{reflection.source_reflection.class_name}' is associated to '#{reflection.through_reflection.class_name}' via :#{reflection.source_reflection.macro}.") diff --git a/activerecord/lib/active_record/associations/nested_has_many_through.rb b/activerecord/lib/active_record/associations/nested_has_many_through.rb deleted file mode 100644 index d699a60edb..0000000000 --- a/activerecord/lib/active_record/associations/nested_has_many_through.rb +++ /dev/null @@ -1,158 +0,0 @@ -# TODO: Remove in the end, when its functionality is fully integrated in ThroughAssociationScope. - -module ActiveRecord - module Associations - module NestedHasManyThrough - def self.included(klass) - klass.alias_method_chain :construct_conditions, :nesting - klass.alias_method_chain :construct_joins, :nesting - end - - def construct_joins_with_nesting(custom_joins = nil) - if nested? - @nested_join_attributes ||= construct_nested_join_attributes - "#{construct_nested_join_attributes[:joins]} #{@reflection.options[:joins]} #{custom_joins}" - else - construct_joins_without_nesting(custom_joins) - end - end - - def construct_conditions_with_nesting - if nested? - @nested_join_attributes ||= construct_nested_join_attributes - if @reflection.through_reflection && @reflection.through_reflection.macro == :belongs_to - "#{@nested_join_attributes[:remote_key]} = #{belongs_to_quoted_key} #{@nested_join_attributes[:conditions]}" - else - "#{@nested_join_attributes[:remote_key]} = #{@owner.quoted_id} #{@nested_join_attributes[:conditions]}" - end - else - construct_conditions_without_nesting - end - end - - protected - - # Given any belongs_to or has_many (including has_many :through) association, - # return the essential components of a join corresponding to that association, namely: - # - # * <tt>:joins</tt>: any additional joins required to get from the association's table - # (reflection.table_name) to the table that's actually joining to the active record's table - # * <tt>:remote_key</tt>: the name of the key in the join table (qualified by table name) which will join - # to a field of the active record's table - # * <tt>:local_key</tt>: the name of the key in the local table (not qualified by table name) which will - # take part in the join - # * <tt>:conditions</tt>: any additional conditions (e.g. filtering by type for a polymorphic association, - # or a :conditions clause explicitly given in the association), including a leading AND - def construct_nested_join_attributes(reflection = @reflection, association_class = reflection.klass, table_ids = {association_class.table_name => 1}) - if (reflection.macro == :has_many || reflection.macro == :has_one) && reflection.through_reflection - construct_has_many_through_attributes(reflection, table_ids) - else - construct_has_many_or_belongs_to_attributes(reflection, association_class, table_ids) - end - end - - def construct_has_many_through_attributes(reflection, table_ids) - # Construct the join components of the source association, so that we have a path from - # the eventual target table of the association up to the table named in :through, and - # all tables involved are allocated table IDs. - source_attrs = construct_nested_join_attributes(reflection.source_reflection, reflection.klass, table_ids) - - # Determine the alias of the :through table; this will be the last table assigned - # when constructing the source join components above. - through_table_alias = through_table_name = reflection.through_reflection.table_name - through_table_alias += "_#{table_ids[through_table_name]}" unless table_ids[through_table_name] == 1 - - # Construct the join components of the through association, so that we have a path to - # the active record's table. - through_attrs = construct_nested_join_attributes(reflection.through_reflection, reflection.through_reflection.klass, table_ids) - - # Any subsequent joins / filters on owner attributes will act on the through association, - # so that's what we return for the conditions/keys of the overall association. - conditions = through_attrs[:conditions] - conditions += " AND #{interpolate_sql(reflection.klass.send(:sanitize_sql, reflection.options[:conditions]))}" if reflection.options[:conditions] - - { - :joins => "%s INNER JOIN %s ON ( %s = %s.%s %s) %s %s" % [ - source_attrs[:joins], - through_table_name == through_table_alias ? through_table_name : "#{through_table_name} #{through_table_alias}", - source_attrs[:remote_key], - through_table_alias, source_attrs[:local_key], - source_attrs[:conditions], - through_attrs[:joins], - reflection.options[:joins] - ], - :remote_key => through_attrs[:remote_key], - :local_key => through_attrs[:local_key], - :conditions => conditions - } - end - - # reflection is not has_many :through; it's a standard has_many / belongs_to instead - # TODO: see if we can defer to rails code here a bit more - def construct_has_many_or_belongs_to_attributes(reflection, association_class, table_ids) - # Determine the alias used for remote_table_name, if any. In all cases this will already - # have been assigned an ID in table_ids (either through being involved in a previous join, - # or - if it's the first table in the query - as the default value of table_ids) - remote_table_alias = remote_table_name = association_class.table_name - remote_table_alias += "_#{table_ids[remote_table_name]}" unless table_ids[remote_table_name] == 1 - - # Assign a new alias for the local table. - local_table_alias = local_table_name = reflection.active_record.table_name - if table_ids[local_table_name] - table_id = table_ids[local_table_name] += 1 - local_table_alias += "_#{table_id}" - else - table_ids[local_table_name] = 1 - end - - conditions = '' - # Add type_condition, if applicable - conditions += " AND #{association_class.send(:type_condition).to_sql}" if association_class.finder_needs_type_condition? - # Add custom conditions - conditions += " AND (#{interpolate_sql(association_class.send(:sanitize_sql, reflection.options[:conditions]))})" if reflection.options[:conditions] - - if reflection.macro == :belongs_to - if reflection.options[:polymorphic] - conditions += " AND #{local_table_alias}.#{reflection.options[:foreign_type]} = #{reflection.active_record.quote_value(association_class.base_class.name.to_s)}" - end - { - :joins => reflection.options[:joins], - :remote_key => "#{remote_table_alias}.#{association_class.primary_key}", - :local_key => reflection.primary_key_name, - :conditions => conditions - } - else - # Association is has_many (without :through) - if reflection.options[:as] - conditions += " AND #{remote_table_alias}.#{reflection.options[:as]}_type = #{reflection.active_record.quote_value(reflection.active_record.base_class.name.to_s)}" - end - { - :joins => "#{reflection.options[:joins]}", - :remote_key => "#{remote_table_alias}.#{reflection.primary_key_name}", - :local_key => reflection.klass.primary_key, - :conditions => conditions - } - end - end - - def belongs_to_quoted_key - attribute = @reflection.through_reflection.primary_key_name - column = @owner.column_for_attribute attribute - - @owner.send(:quote_value, @owner.send(attribute), column) - end - - def nested? - through_source_reflection? || through_through_reflection? - end - - def through_source_reflection? - @reflection.source_reflection && @reflection.source_reflection.options[:through] - end - - def through_through_reflection? - @reflection.through_reflection && @reflection.through_reflection.options[:through] - end - end - end -end diff --git a/activerecord/lib/active_record/associations/through_association_scope.rb b/activerecord/lib/active_record/associations/through_association_scope.rb index 649bbd206a..abe7af418d 100644 --- a/activerecord/lib/active_record/associations/through_association_scope.rb +++ b/activerecord/lib/active_record/associations/through_association_scope.rb @@ -61,10 +61,6 @@ module ActiveRecord end def construct_joins(custom_joins = nil) - # TODO: Remove this at the end - #p @reflection.through_reflection_chain - #p @reflection.through_conditions - "#{construct_through_joins} #{@reflection.options[:joins]} #{custom_joins}" end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 3448cc506c..1ea892895f 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -131,14 +131,6 @@ module ActiveRecord @sanitized_conditions ||= klass.send(:sanitize_sql, options[:conditions]) if options[:conditions] end - # TODO: Remove these in the final patch. I am just using them for debugging etc. - def inspect - "#<#{code_name}>" - end - def code_name - "#{active_record.name}.#{macro} :#{name}" - end - private def derive_class_name name.to_s.camelize @@ -325,16 +317,6 @@ module ActiveRecord def belongs_to? macro == :belongs_to end - - # TODO: Remove for final patch. Just here for debugging. - def inspect - str = "#<#{code_name}, @source_reflection=" - str << (source_reflection.respond_to?(:code_name) ? source_reflection.code_name : source_reflection.inspect) - str << ", @through_reflection=" - str << (through_reflection.respond_to?(:code_name) ? through_reflection.code_name : through_reflection.inspect) - str << ">" - str - end private def derive_class_name @@ -497,12 +479,6 @@ module ActiveRecord raise HasManyThroughAssociationPolymorphicError.new(active_record.name, self, source_reflection) end - # TODO: Presumably remove the HasManyThroughSourceAssociationMacroError class and delete these lines. - # Think about whether there are any cases which should still be disallowed. - # unless [:belongs_to, :has_many, :has_one].include?(source_reflection.macro) && source_reflection.options[:through].nil? - # raise HasManyThroughSourceAssociationMacroError.new(self) - # end - check_validity_of_inverse! end diff --git a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb index 3a4601b032..23fa1709ce 100644 --- a/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/nested_has_many_through_associations_test.rb @@ -23,11 +23,6 @@ require 'models/categorization' require 'models/membership' require 'models/essay' -# NOTE: Some of these tests might not really test "nested" HMT associations, as opposed to ones which -# are just one level deep. But it's all the same thing really, as the "nested" code is being -# written in a generic way which applies to "non-nested" HMT associations too. So let's just shove -# all useful tests in here for now and then work out where they ought to live properly later. - class NestedHasManyThroughAssociationsTest < ActiveRecord::TestCase fixtures :authors, :books, :posts, :subscriptions, :subscribers, :tags, :taggings, :people, :readers, :references, :jobs, :ratings, :comments, :members, :member_details, |