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, #class_name, #primary_key_type, #quoted_table_name, #table_name
Constructor Details
#initialize(delegate_reflection) ⇒ ThroughReflection
Returns a new instance of ThroughReflection.
633 634 635 636 637 |
# File 'lib/active_record/reflection.rb', line 633 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:
629 630 631 |
# File 'lib/active_record/reflection.rb', line 629 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.
770 771 772 773 774 |
# File 'lib/active_record/reflection.rb', line 770 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>]
697 698 699 700 701 702 703 704 705 |
# File 'lib/active_record/reflection.rb', line 697 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
826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 |
# File 'lib/active_record/reflection.rb', line 826 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:
822 823 824 |
# File 'lib/active_record/reflection.rb', line 822 def join_id_for(owner) # :nodoc: source_reflection.join_id_for(owner) end |
#join_keys(assoc_klass) ⇒ Object
748 749 750 |
# File 'lib/active_record/reflection.rb', line 748 def join_keys(assoc_klass) source_reflection.join_keys(assoc_klass) end |
#klass ⇒ Object
639 640 641 |
# File 'lib/active_record/reflection.rb', line 639 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
763 764 765 |
# File 'lib/active_record/reflection.rb', line 763 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.
726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 |
# File 'lib/active_record/reflection.rb', line 726 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
753 754 755 756 757 758 759 760 |
# File 'lib/active_record/reflection.rb', line 753 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
814 815 816 |
# File 'lib/active_record/reflection.rb', line 814 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">
660 661 662 |
# File 'lib/active_record/reflection.rb', line 660 def source_reflection through_reflection.klass._reflect_on_association(source_reflection_name) end |
#source_reflection_name ⇒ Object
:nodoc:
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 |
# File 'lib/active_record/reflection.rb', line 791 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]
787 788 789 |
# File 'lib/active_record/reflection.rb', line 787 def source_reflection_names [:source] ? [[:source]] : [name.to_s.singularize, name].uniq end |
#through_options ⇒ Object
818 819 820 |
# File 'lib/active_record/reflection.rb', line 818 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">
676 677 678 |
# File 'lib/active_record/reflection.rb', line 676 def through_reflection active_record._reflect_on_association([:through]) end |