Permalink
Browse files

STI associations are now aliased to the table name for backwards comp…

…atibility. Added docs for table aliasing [Rick Olson]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@4015 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
1 parent c05c22a commit ed10f873a17dacb60f503102a023233b9589f598 @technoweenie technoweenie committed Mar 23, 2006
Showing with 54 additions and 9 deletions.
  1. +54 −9 activerecord/lib/active_record/associations.rb
@@ -261,9 +261,57 @@ def clear_association_cache #:nodoc:
# in both conditions and orders. So :order => "posts.id DESC" will work while :order => "id DESC" will not. This may require that
# you alter the :order and :conditions on the association definitions themselves.
#
- # It's currently not possible to use eager loading on multiple associations from the same table. Eager loading will also not pull
+ # It's currently not possible to use eager loading on multiple associations from the same table. Eager loading will not pull
# additional attributes on join tables, so "rich associations" with has_and_belongs_to_many is not a good fit for eager loading.
#
+ # == Table Aliasing
+ #
+ # ActiveRecord uses table aliasing in the case that a table is referenced multiple times in a join. If a table is referenced only once,
+ # the standard table name is used. The second time, the table is aliased as #{reflection_name}_#{parent_table_name}. Indexes are appended
+ # for any more successive uses of the table name.
+ #
+ # Post.find :all, :include => :comments
+ # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ...
+ # Post.find :all, :include => :special_comments # STI
+ # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... AND comments.type = 'SpecialComment'
+ # Post.find :all, :include => [:comments, :special_comments] # special_comments is the reflection name, posts is the parent table name
+ # # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... LEFT OUTER JOIN comments special_comments_posts
+ #
+ # Acts as tree example:
+ #
+ # TreeMixin.find :all, :include => :children
+ # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
+ # TreeMixin.find :all, :include => {:children => :parent} # using cascading eager includes
+ # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
+ # LEFT OUTER JOIN parents_mixins ...
+ # TreeMixin.find :all, :include => {:children => {:parent => :children}}
+ # # => SELECT ... FROM mixins LEFT OUTER JOIN mixins childrens_mixins ...
+ # LEFT OUTER JOIN parents_mixins ...
+ # LEFT OUTER JOIN mixins childrens_mixins_2
+ #
+ # Has and Belongs to Many join tables use the same idea, but add a _join suffix:
+ #
+ # Post.find :all, :include => :categories
+ # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
+ # Post.find :all, :include => {:categories => :posts}
+ # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
+ # LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories
+ # Post.find :all, :include => {:categories => {:posts => :categories}}
+ # # => SELECT ... FROM posts LEFT OUTER JOIN categories_posts ... LEFT OUTER JOIN categories ...
+ # LEFT OUTER JOIN categories_posts posts_categories_join LEFT OUTER JOIN posts posts_categories
+ # LEFT OUTER JOIN categories_posts categories_posts_join LEFT OUTER JOIN categories categories_posts
+ #
+ # If you wish to specify your own custom joins using a :joins option, those table names will take precedence over the eager associations..
+ #
+ # Post.find :all, :include => :comments, :joins => "inner join comments ..."
+ # # => SELECT ... FROM posts LEFT OUTER JOIN comments_posts ON ... INNER JOIN comments ...
+ # Post.find :all, :include => [:comments, :special_comments], :joins => "inner join comments ..."
+ # # => SELECT ... FROM posts LEFT OUTER JOIN comments comments_posts ON ...
+ # LEFT OUTER JOIN comments special_comments_posts ...
+ # INNER JOIN comments ...
+ #
+ # Table aliases are automatically truncated according to the maximum length of table identifiers according to the specific database.
+ #
# == Modules
#
# By default, associations will look for objects within the current module scope. Consider:
@@ -1257,10 +1305,10 @@ def initialize(reflection, join_dependency, parent = nil)
@parent = parent
@reflection = reflection
@aliased_prefix = "t#{ join_dependency.joins.size }"
- @aliased_table_name = sti? ? pluralize(reflection.name) : table_name # start with the table name
- @parent_table_name = sti? ? pluralize(parent.active_record.name.underscore) : parent.active_record.table_name
+ @aliased_table_name = table_name # start with the table name
+ @parent_table_name = parent.active_record.table_name
- if !parent.table_joins.blank? && parent.table_joins =~ %r{#{aliased_table_name}}
+ if !parent.table_joins.blank? && parent.table_joins.to_s.downcase =~ %r{join(\s+\w+)?\s+#{aliased_table_name.downcase}\son}
join_dependency.table_aliases[aliased_table_name] += 1
end
@@ -1270,6 +1318,7 @@ def initialize(reflection, join_dependency, parent = nil)
table_index = join_dependency.table_aliases[aliased_table_name]
@aliased_table_name = @aliased_table_name[0..active_record.connection.table_alias_length-3] + "_#{table_index+1}" if table_index > 0
end
+
if reflection.macro == :has_and_belongs_to_many || (reflection.macro == :has_many && reflection.options[:through])
@aliased_join_table_name = reflection.macro == :has_and_belongs_to_many ? reflection.options[:join_table] : parent.active_record.reflect_on_association(reflection.options[:through]).klass.table_name
unless join_dependency.table_aliases[aliased_join_table_name].zero?
@@ -1362,16 +1411,12 @@ def association_join
join << %(AND %s.%s = %s ) % [
aliased_table_name,
reflection.active_record.connection.quote_column_name(reflection.active_record.inheritance_column),
- klass.quote(klass.name)] if sti?
+ klass.quote(klass.name)] unless klass.descends_from_active_record?
join << "AND #{interpolate_sql(sanitize_sql(reflection.options[:conditions]))} " if reflection.options[:conditions]
join
end
protected
- def sti?
- !klass.descends_from_active_record?
- end
-
def pluralize(table_name)
ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name
end

0 comments on commit ed10f87

Please sign in to comment.