Class: ActiveRecord::Reflection::ThroughReflection
- Inherits:
-
AbstractReflection
- Object
- AbstractReflection
- 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.
Instance Attribute Summary collapse
-
#delegate_reflection ⇒ Object
readonly
:nodoc:.
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(delegate_reflection) ⇒ ThroughReflection
constructor
A new instance of ThroughReflection.
-
#join_id_for(owner) ⇒ Object
:nodoc:.
- #join_keys(assoc_klass) ⇒ Object
- #klass ⇒ Object
-
#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 AbstractReflection
#build_association, #check_validity_of_inverse!, #class_name, #inverse_of, #primary_key_type, #quoted_table_name, #table_name
Constructor Details
#initialize(delegate_reflection) ⇒ ThroughReflection
Returns a new instance of ThroughReflection.
643 644 645 646 647 |
# File 'lib/active_record/reflection.rb', line 643 def initialize(delegate_reflection) @delegate_reflection = delegate_reflection @klass = delegate_reflection.[:anonymous_class] @source_reflection_name = delegate_reflection.[:source] end |
Instance Attribute Details
#delegate_reflection ⇒ Object (readonly)
:nodoc:
639 640 641 |
# File 'lib/active_record/reflection.rb', line 639 def delegate_reflection @delegate_reflection 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.
780 781 782 783 784 |
# File 'lib/active_record/reflection.rb', line 780 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: @delegate_reflection=#<ActiveRecord::Reflection::HasManyReflection: @name=:tags...>,
<ActiveRecord::Reflection::HasManyReflection: @name=:taggings, @options={}, @active_record=Post>]
707 708 709 710 711 712 713 714 715 |
# File 'lib/active_record/reflection.rb', line 707 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
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 |
# File 'lib/active_record/reflection.rb', line 836 def check_validity! if through_reflection.nil? raise HasManyThroughAssociationNotFoundError.new(active_record.name, self) end if through_reflection.polymorphic? if has_one? raise HasOneAssociationPolymorphicThroughError.new(active_record.name, self) else raise HasManyThroughAssociationPolymorphicThroughError.new(active_record.name, self) end end if source_reflection.nil? raise HasManyThroughSourceAssociationNotFoundError.new(self) end if [:source_type] && !source_reflection.polymorphic? 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 has_one? && through_reflection.collection? raise HasOneThroughCantAssociateThroughCollection.new(active_record.name, self, through_reflection) end check_validity_of_inverse! end |
#join_id_for(owner) ⇒ Object
:nodoc:
832 833 834 |
# File 'lib/active_record/reflection.rb', line 832 def join_id_for(owner) # :nodoc: source_reflection.join_id_for(owner) end |
#join_keys(assoc_klass) ⇒ Object
758 759 760 |
# File 'lib/active_record/reflection.rb', line 758 def join_keys(assoc_klass) source_reflection.join_keys(assoc_klass) end |
#klass ⇒ Object
649 650 651 |
# File 'lib/active_record/reflection.rb', line 649 def klass @klass ||= delegate_reflection.compute_class(class_name) end |
#nested? ⇒ Boolean
A through association is nested if there would be more than one join table
773 774 775 |
# File 'lib/active_record/reflection.rb', line 773 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.
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 |
# File 'lib/active_record/reflection.rb', line 736 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
763 764 765 766 767 768 769 770 |
# File 'lib/active_record/reflection.rb', line 763 def source_macro ActiveSupport::Deprecation.warn(<<-MSG.squish) ActiveRecord::Base.source_macro is deprecated and will be removed without replacement. MSG source_reflection.source_macro end |
#source_options ⇒ Object
824 825 826 |
# File 'lib/active_record/reflection.rb', line 824 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::BelongsToReflection: @name=:tag, @active_record=Tagging, @plural_name="tags">
670 671 672 |
# File 'lib/active_record/reflection.rb', line 670 def source_reflection through_reflection.klass._reflect_on_association(source_reflection_name) end |
#source_reflection_name ⇒ Object
:nodoc:
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 |
# File 'lib/active_record/reflection.rb', line 801 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 \ "Ambiguous source reflection for through association. Please " \ "specify a :source directive on your declaration like:\n" \ "\n" \ " class #{active_record.name} < ActiveRecord::Base\n" \ " #{macro} :#{name}, #{}\n" \ " end" 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]
797 798 799 |
# File 'lib/active_record/reflection.rb', line 797 def source_reflection_names [:source] ? [[:source]] : [name.to_s.singularize, name].uniq end |
#through_options ⇒ Object
828 829 830 |
# File 'lib/active_record/reflection.rb', line 828 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::HasManyReflection: @name=:taggings, @active_record=Post, @plural_name="taggings">
686 687 688 |
# File 'lib/active_record/reflection.rb', line 686 def through_reflection active_record._reflect_on_association([:through]) end |