mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
Remove various comments and code which were just being used during the development of nested through association support (OMFGZ, I might just have nearly finished this\!
This commit is contained in:
@@ -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}.")
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user