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
: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?, #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.
639 640 641 642 643 |
# File 'lib/active_record/reflection.rb', line 639 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>]
575 576 577 578 579 580 581 582 583 |
# File 'lib/active_record/reflection.rb', line 575 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
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 718 719 |
# File 'lib/active_record/reflection.rb', line 693 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
632 633 634 |
# File 'lib/active_record/reflection.rb', line 632 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.
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 |
# File 'lib/active_record/reflection.rb', line 604 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
627 628 629 |
# File 'lib/active_record/reflection.rb', line 627 def source_macro source_reflection.source_macro end |
#source_options ⇒ Object
685 686 687 |
# File 'lib/active_record/reflection.rb', line 685 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 539 540 |
# File 'lib/active_record/reflection.rb', line 536 def source_reflection if source_reflection_name through_reflection.klass._reflect_on_association(source_reflection_name) end end |
#source_reflection_name ⇒ Object
:nodoc:
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 |
# File 'lib/active_record/reflection.rb', line 660 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 <<-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]
656 657 658 |
# File 'lib/active_record/reflection.rb', line 656 def source_reflection_names ([:source] ? [[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym }.uniq end |
#through_options ⇒ Object
689 690 691 |
# File 'lib/active_record/reflection.rb', line 689 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">
554 555 556 |
# File 'lib/active_record/reflection.rb', line 554 def through_reflection active_record._reflect_on_association([:through]) end |