aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record/associations.rb8
-rw-r--r--activerecord/lib/active_record/associations/nested_has_many_through.rb158
-rw-r--r--activerecord/lib/active_record/associations/through_association_scope.rb4
-rw-r--r--activerecord/lib/active_record/reflection.rb24
-rw-r--r--activerecord/test/cases/associations/nested_has_many_through_associations_test.rb5
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,