Class: ActiveRecord::Reflection::ThroughReflection
- Inherits:
-
AssociationReflection
- Object
- MacroReflection
- AssociationReflection
- ActiveRecord::Reflection::ThroughReflection
- Defined in:
- 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
#foreign_type, #parent_reflection, #type
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
:throughsource reflection names in both singular and plural form. - #through_options ⇒ Object
-
#through_reflection ⇒ Object
Returns the AssociationReflection object specified in the
:throughoption 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?, #constructable?, #counter_cache_column, #foreign_key, #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.
514 515 516 517 |
# File 'lib/active_record/reflection.rb', line 514 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.
637 638 639 640 641 |
# File 'lib/active_record/reflection.rb', line 637 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
= Post.reflect_on_association(:tags)
.chain
# => [<ActiveRecord::Reflection::ThroughReflection: @macro=:has_many, @name=:tags, @options={:through=>:taggings}, @active_record=Post>,
<ActiveRecord::Reflection::AssociationReflection: @macro=:has_many, @name=:taggings, ={}, @active_record=Post>]
573 574 575 576 577 578 579 580 581 |
# File 'lib/active_record/reflection.rb', line 573 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
691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 |
# File 'lib/active_record/reflection.rb', line 691 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
630 631 632 |
# File 'lib/active_record/reflection.rb', line 630 def nested? chain.length > 2 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.
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 |
# File 'lib/active_record/reflection.rb', line 602 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.map(&:dup) if [:source_type] type = foreign_type source_type = [:source_type] through_scope_chain.first << lambda { |object| where(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
625 626 627 |
# File 'lib/active_record/reflection.rb', line 625 def source_macro source_reflection.source_macro end |
#source_options ⇒ Object
683 684 685 |
# File 'lib/active_record/reflection.rb', line 683 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">
536 537 538 |
# File 'lib/active_record/reflection.rb', line 536 def source_reflection through_reflection.klass._reflect_on_association(source_reflection_name) end |
#source_reflection_name ⇒ Object
:nodoc:
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 |
# File 'lib/active_record/reflection.rb', line 658 def source_reflection_name # :nodoc: return @source_reflection_name.to_sym 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 "Ambiguous source reflection for through association. Please specify a :source\ndirective on your declaration like:\n\n class \#{active_record.name} < ActiveRecord::Base\n \#{macro} :\#{name}, \#{example_options}\n end\n\n eowarn\n end\n\n @source_reflection_name = names.first\nend\n" |
#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]
654 655 656 |
# File 'lib/active_record/reflection.rb', line 654 def source_reflection_names ([:source] ? [[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym }.uniq end |
#through_options ⇒ Object
687 688 689 |
# File 'lib/active_record/reflection.rb', line 687 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">
552 553 554 |
# File 'lib/active_record/reflection.rb', line 552 def through_reflection active_record._reflect_on_association([:through]) end |