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.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#delegate_reflection ⇒ Object
readonly
:nodoc:.
Instance Method Summary collapse
- #add_as_polymorphic_through(reflection, seed) ⇒ Object
- #add_as_source(seed) ⇒ Object
- #add_as_through(seed) ⇒ Object
-
#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.
- #check_validity! ⇒ Object
-
#clear_association_scope_cache ⇒ Object
This is for clearing cache on the reflection.
-
#collect_join_chain ⇒ Object
Returns an array of reflections which are involved in this association.
- #collect_join_reflections(seed) ⇒ Object
- #constraints ⇒ Object
- #has_scope? ⇒ Boolean
-
#initialize(delegate_reflection) ⇒ ThroughReflection
constructor
A new instance of ThroughReflection.
-
#join_id_for(owner) ⇒ Object
:nodoc:.
- #join_keys(association_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_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. - #through_reflection? ⇒ Boolean
Methods inherited from AbstractReflection
#alias_candidate, #build_association, #chain, #check_validity_of_inverse!, #class_name, #counter_cache_column, #counter_must_be_updated_by_has_many?, #has_cached_counter?, #inverse_of, #inverse_updates_counter_in_memory?, #inverse_which_updates_counter_cache, #primary_key_type, #quoted_table_name, #table_name
Constructor Details
#initialize(delegate_reflection) ⇒ ThroughReflection
Returns a new instance of ThroughReflection.
705 706 707 708 709 |
# File 'lib/active_record/reflection.rb', line 705 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:
701 702 703 |
# File 'lib/active_record/reflection.rb', line 701 def delegate_reflection @delegate_reflection end |
Instance Method Details
#add_as_polymorphic_through(reflection, seed) ⇒ Object
942 943 944 |
# File 'lib/active_record/reflection.rb', line 942 def add_as_polymorphic_through(reflection, seed) collect_join_reflections(seed + [PolymorphicReflection.new(self, reflection)]) end |
#add_as_source(seed) ⇒ Object
938 939 940 |
# File 'lib/active_record/reflection.rb', line 938 def add_as_source(seed) collect_join_reflections seed end |
#add_as_through(seed) ⇒ Object
946 947 948 |
# File 'lib/active_record/reflection.rb', line 946 def add_as_through(seed) collect_join_reflections(seed + [self]) end |
#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.
844 845 846 847 848 |
# File 'lib/active_record/reflection.rb', line 844 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 |
#check_validity! ⇒ Object
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 |
# File 'lib/active_record/reflection.rb', line 900 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 |
#clear_association_scope_cache ⇒ Object
This is for clearing cache on the reflection. Useful for tests that need to compare SQL queries on associations.
779 780 781 782 783 |
# File 'lib/active_record/reflection.rb', line 779 def clear_association_scope_cache # :nodoc: delegate_reflection.clear_association_scope_cache source_reflection.clear_association_scope_cache through_reflection.clear_association_scope_cache end |
#collect_join_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>]
773 774 775 |
# File 'lib/active_record/reflection.rb', line 773 def collect_join_chain collect_join_reflections [self] end |
#collect_join_reflections(seed) ⇒ Object
950 951 952 953 954 955 956 957 |
# File 'lib/active_record/reflection.rb', line 950 def collect_join_reflections(seed) a = source_reflection.add_as_source seed if [:source_type] through_reflection.add_as_polymorphic_through self, a else through_reflection.add_as_through a end end |
#constraints ⇒ Object
932 933 934 935 936 |
# File 'lib/active_record/reflection.rb', line 932 def constraints scope_chain = source_reflection.constraints scope_chain << scope if scope scope_chain end |
#has_scope? ⇒ Boolean
826 827 828 829 830 |
# File 'lib/active_record/reflection.rb', line 826 def has_scope? scope || [:source_type] || source_reflection.has_scope? || through_reflection.has_scope? end |
#join_id_for(owner) ⇒ Object
:nodoc:
896 897 898 |
# File 'lib/active_record/reflection.rb', line 896 def join_id_for(owner) # :nodoc: source_reflection.join_id_for(owner) end |
#join_keys(association_klass) ⇒ Object
832 833 834 |
# File 'lib/active_record/reflection.rb', line 832 def join_keys(association_klass) source_reflection.join_keys(association_klass) end |
#klass ⇒ Object
715 716 717 |
# File 'lib/active_record/reflection.rb', line 715 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
837 838 839 |
# File 'lib/active_record/reflection.rb', line 837 def nested? source_reflection.through_reflection? || through_reflection.through_reflection? 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.
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 |
# File 'lib/active_record/reflection.rb', line 804 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_options ⇒ Object
888 889 890 |
# File 'lib/active_record/reflection.rb', line 888 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">
736 737 738 |
# File 'lib/active_record/reflection.rb', line 736 def source_reflection through_reflection.klass._reflect_on_association(source_reflection_name) end |
#source_reflection_name ⇒ Object
:nodoc:
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 |
# File 'lib/active_record/reflection.rb', line 865 def source_reflection_name # :nodoc: return @source_reflection_name if @source_reflection_name names = [name.to_s.singularize, name].collect(&: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]
861 862 863 |
# File 'lib/active_record/reflection.rb', line 861 def source_reflection_names [:source] ? [[:source]] : [name.to_s.singularize, name].uniq end |
#through_options ⇒ Object
892 893 894 |
# File 'lib/active_record/reflection.rb', line 892 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">
752 753 754 |
# File 'lib/active_record/reflection.rb', line 752 def through_reflection active_record._reflect_on_association([:through]) end |
#through_reflection? ⇒ Boolean
711 712 713 |
# File 'lib/active_record/reflection.rb', line 711 def through_reflection? true end |