Class: ActiveRecord::Reflection::ThroughReflection
- Inherits:
-
AssociationReflection
- Object
- MacroReflection
- AssociationReflection
- ActiveRecord::Reflection::ThroughReflection
- Defined in:
- activerecord/lib/active_record/reflection.rb
Overview
Holds all the meta-data about a :through association as it was specified in the Active Record class.
Constant Summary
Constants inherited from AssociationReflection
AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS, AssociationReflection::VALID_AUTOMATIC_INVERSE_MACROS
Instance Attribute Summary
Attributes inherited from AssociationReflection
Attributes inherited from MacroReflection
#active_record, #macro, #name, #options, #plural_name, #scope
Instance Method Summary collapse
-
#association_primary_key(klass = nil) ⇒ Object
We want to use the klass from this reflection, rather than just delegate straight to the source_reflection, because the source_reflection may be polymorphic.
-
#chain ⇒ Object
Returns an array of reflections which are involved in this association.
- #check_validity! ⇒ Object
-
#initialize(macro, name, scope, options, active_record) ⇒ ThroughReflection
constructor
A new instance of ThroughReflection.
-
#nested? ⇒ Boolean
A through association is nested if there would be more than one join table.
-
#scope_chain ⇒ Object
Consider the following example:.
-
#source_macro ⇒ Object
The macro used by the source association.
- #source_options ⇒ Object
-
#source_reflection ⇒ Object
Returns the source of the through reflection.
-
#source_reflection_name ⇒ Object
:nodoc:.
-
#source_reflection_names ⇒ Object
Gets an array of possible
:through
source reflection names in both singular and plural form. - #through_options ⇒ Object
-
#through_reflection ⇒ Object
Returns the AssociationReflection object specified in the
:through
option of a HasManyThrough or HasOneThrough association.
Methods inherited from AssociationReflection
#active_record_primary_key, #association_class, #association_foreign_key, #belongs_to?, #build_association, #check_validity_of_inverse!, #collection?, #counter_cache_column, #foreign_key, #has_and_belongs_to_many?, #has_inverse?, #inverse_of, #join_table, #klass, #polymorphic?, #polymorphic_inverse_of, #primary_key_column, #quoted_table_name, #table_name, #validate?
Methods inherited from MacroReflection
#==, #autosave=, #class_name, #klass
Constructor Details
#initialize(macro, name, scope, options, active_record) ⇒ ThroughReflection
Returns a new instance of ThroughReflection.
477 478 479 480 |
# File 'activerecord/lib/active_record/reflection.rb', line 477 def initialize(macro, name, scope, , active_record) super @source_reflection_name = [:source] end |
Instance Method Details
#association_primary_key(klass = nil) ⇒ Object
We want to use the klass from this reflection, rather than just delegate straight to the source_reflection, because the source_reflection may be polymorphic. We still need to respect the source_reflection’s :primary_key option, though.
597 598 599 600 601 |
# File 'activerecord/lib/active_record/reflection.rb', line 597 def association_primary_key(klass = nil) # Get the "actual" source reflection if the immediate source reflection has a # source reflection itself actual_source_reflection.[:primary_key] || primary_key(klass || self.klass) end |
#chain ⇒ Object
Returns an array of reflections which are involved in this association. Each item in the array corresponds to a table which will be part of the query for this association.
The chain is built by recursively calling #chain on the source reflection and the through reflection. The base case for the recursion is a normal association, which just returns
- self
-
as its #chain.
class Post < ActiveRecord::Base
has_many :taggings
has_many :tags, through: :taggings
end
tags_reflection = Post.reflect_on_association(:tags)
tags_reflection.chain
# => [<ActiveRecord::Reflection::ThroughReflection: @macro=:has_many, @name=:tags, @options={:through=>:taggings}, @active_record=Post>,
<ActiveRecord::Reflection::AssociationReflection: @macro=:has_many, @name=:taggings, @options={}, @active_record=Post>]
536 537 538 539 540 541 542 543 544 |
# File 'activerecord/lib/active_record/reflection.rb', line 536 def chain @chain ||= begin a = source_reflection.chain b = through_reflection.chain chain = a + b chain[0] = self # Use self so we don't lose the information from :source_type chain end end |
#check_validity! ⇒ Object
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 |
# File 'activerecord/lib/active_record/reflection.rb', line 651 def check_validity! if through_reflection.nil? raise HasManyThroughAssociationNotFoundError.new(active_record.name, self) end if through_reflection.[:polymorphic] raise HasManyThroughAssociationPolymorphicThroughError.new(active_record.name, self) end if source_reflection.nil? raise HasManyThroughSourceAssociationNotFoundError.new(self) end if [:source_type] && source_reflection.[:polymorphic].nil? raise HasManyThroughAssociationPointlessSourceTypeError.new(active_record.name, self, source_reflection) end if source_reflection.[:polymorphic] && [:source_type].nil? raise HasManyThroughAssociationPolymorphicSourceError.new(active_record.name, self, source_reflection) end if macro == :has_one && through_reflection.collection? raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection) end check_validity_of_inverse! end |
#nested? ⇒ Boolean
A through association is nested if there would be more than one join table
590 591 592 |
# File 'activerecord/lib/active_record/reflection.rb', line 590 def nested? chain.length > 2 || through_reflection.has_and_belongs_to_many? end |
#scope_chain ⇒ Object
Consider the following example:
class Person
has_many :articles
has_many :comment_tags, through: :articles
end
class Article
has_many :comments
has_many :comment_tags, through: :comments, source: :tags
end
class Comment
has_many :tags
end
There may be scopes on Person.comment_tags, Article.comment_tags and/or Comment.tags, but only Comment.tags will be represented in the #chain. So this method creates an array of scopes corresponding to the chain.
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 |
# File 'activerecord/lib/active_record/reflection.rb', line 565 def scope_chain @scope_chain ||= begin scope_chain = source_reflection.scope_chain.map(&:dup) # Add to it the scope from this reflection (if any) scope_chain.first << scope if scope through_scope_chain = through_reflection.scope_chain if [:source_type] through_scope_chain.first << through_reflection.klass.where(foreign_type => [:source_type]) end # Recursively fill out the rest of the array from the through reflection scope_chain + through_scope_chain end end |
#source_macro ⇒ Object
The macro used by the source association
585 586 587 |
# File 'activerecord/lib/active_record/reflection.rb', line 585 def source_macro source_reflection.source_macro end |
#source_options ⇒ Object
643 644 645 |
# File 'activerecord/lib/active_record/reflection.rb', line 643 def source_reflection. end |
#source_reflection ⇒ Object
Returns the source of the through reflection. It checks both a singularized and pluralized form for :belongs_to
or :has_many
.
class Post < ActiveRecord::Base
has_many :taggings
has_many :tags, through: :taggings
end
class Tagging < ActiveRecord::Base
belongs_to :post
belongs_to :tag
end
= Post.reflect_on_association(:tags)
.source_reflection
# => <ActiveRecord::Reflection::AssociationReflection: @macro=:belongs_to, @name=:tag, @active_record=Tagging, @plural_name="tags">
499 500 501 |
# File 'activerecord/lib/active_record/reflection.rb', line 499 def source_reflection through_reflection.klass.reflect_on_association(source_reflection_name) end |
#source_reflection_name ⇒ Object
:nodoc:
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 |
# File 'activerecord/lib/active_record/reflection.rb', line 618 def source_reflection_name # :nodoc: return @source_reflection_name if @source_reflection_name names = [name.to_s.singularize, name].collect { |n| n.to_sym }.uniq names = names.find_all { |n| through_reflection.klass.reflect_on_association(n) } if names.length > 1 = .dup [:source] = source_reflection_names.first ActiveSupport::Deprecation.warn <<-eowarn Ambiguous source reflection for through association. Please specify a :source directive on your declaration like: class #{active_record.name} < ActiveRecord::Base #{macro} :#{name}, #{} end eowarn end @source_reflection_name = names.first end |
#source_reflection_names ⇒ Object
Gets an array of possible :through
source reflection names in both singular and plural form.
class Post < ActiveRecord::Base
has_many :taggings
has_many :tags, through: :taggings
end
= Post.reflect_on_association(:tags)
.source_reflection_names
# => [:tag, :tags]
614 615 616 |
# File 'activerecord/lib/active_record/reflection.rb', line 614 def source_reflection_names ([:source] ? [[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym }.uniq end |
#through_options ⇒ Object
647 648 649 |
# File 'activerecord/lib/active_record/reflection.rb', line 647 def through_reflection. end |
#through_reflection ⇒ Object
Returns the AssociationReflection object specified in the :through
option of a HasManyThrough or HasOneThrough association.
class Post < ActiveRecord::Base
has_many :taggings
has_many :tags, through: :taggings
end
= Post.reflect_on_association(:tags)
.through_reflection
# => <ActiveRecord::Reflection::AssociationReflection: @macro=:has_many, @name=:taggings, @active_record=Post, @plural_name="taggings">
515 516 517 |
# File 'activerecord/lib/active_record/reflection.rb', line 515 def through_reflection active_record.reflect_on_association([:through]) end |