class ActiveRecord::Reflection::ThroughReflection
:nodoc:
in the Active Record class.
Holds all the metadata about a :through association as it was specified
def actual_source_reflection # FIXME: this is a horrible name
def actual_source_reflection # FIXME: this is a horrible name source_reflection.actual_source_reflection end
def add_as_polymorphic_through(reflection, seed)
def add_as_polymorphic_through(reflection, seed) collect_join_reflections(seed + [PolymorphicReflection.new(self, reflection)]) end
def add_as_source(seed)
def add_as_source(seed) collect_join_reflections seed end
def add_as_through(seed)
def add_as_through(seed) collect_join_reflections(seed + [self]) end
def association_primary_key(klass = nil)
the source_reflection, because the source_reflection may be polymorphic. We still
We want to use the klass from this reflection, rather than just delegate straight to
def association_primary_key(klass = nil) # Get the "actual" source reflection if the immediate source reflection has a # source reflection itself if primary_key = actual_source_reflection.options[:primary_key] @association_primary_key ||= -primary_key.to_s else primary_key(klass || self.klass) end end
def check_validity!
def check_validity! if through_reflection.nil? raise HasManyThroughAssociationNotFoundError.new(active_record, 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 options[:source_type] && !source_reflection.polymorphic? raise HasManyThroughAssociationPointlessSourceTypeError.new(active_record.name, self, source_reflection) end if source_reflection.polymorphic? && options[: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 if parent_reflection.nil? reflections = active_record.reflections.keys.map(&:to_sym) if reflections.index(through_reflection.name) > reflections.index(name) raise HasManyThroughOrderError.new(active_record.name, self, through_reflection) end end check_validity_of_inverse! end
def clear_association_scope_cache # :nodoc:
SQL queries on associations.
This is for clearing cache on the reflection. Useful for tests that need to compare
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
def collect_join_chain
# => [
tags_reflection.chain
tags_reflection = Post.reflect_on_association(:tags)
end
has_many :tags, through: :taggings
has_many :taggings
class Post < ActiveRecord::Base
[self] as its #chain.
reflection. The base case for the recursion is a normal association, which just returns
The chain is built by recursively calling #chain on the source reflection and the through
array corresponds to a table which will be part of the query for this association.
Returns an array of reflections which are involved in this association. Each item in the
def collect_join_chain collect_join_reflections [self] end
def collect_join_reflections(seed)
def collect_join_reflections(seed) a = source_reflection.add_as_source seed if options[:source_type] through_reflection.add_as_polymorphic_through self, a else through_reflection.add_as_through a end end
def constraints
def constraints scope_chain = source_reflection.constraints scope_chain << scope if scope scope_chain end
def derive_class_name
def derive_class_name # get the class_name of the belongs_to association of the through reflection options[:source_type] || source_reflection.class_name end
def has_scope?
def has_scope? scope || options[:source_type] || source_reflection.has_scope? || through_reflection.has_scope? end
def initialize(delegate_reflection)
def initialize(delegate_reflection) @delegate_reflection = delegate_reflection @klass = delegate_reflection.options[:anonymous_class] @source_reflection_name = delegate_reflection.options[:source] ensure_option_not_given_as_class!(:source_type) end
def inverse_name; delegate_reflection.send(:inverse_name); end
def inverse_name; delegate_reflection.send(:inverse_name); end
def join_primary_key(klass = self.klass)
def join_primary_key(klass = self.klass) source_reflection.join_primary_key(klass) end
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc:
def join_scopes(table, predicate_builder, klass = self.klass, record = nil) # :nodoc: source_reflection.join_scopes(table, predicate_builder, klass, record) + super end
def klass
def klass @klass ||= delegate_reflection.compute_class(class_name) end
def nested?
def nested? source_reflection.through_reflection? || through_reflection.through_reflection? end
def scopes
def scopes source_reflection.scopes + super end
def source_options
def source_options source_reflection.options end
def source_reflection
# =>
tags_reflection.source_reflection
tags_reflection = Post.reflect_on_association(:tags)
end
belongs_to :tag
belongs_to :post
class Tagging < ActiveRecord::Base
end
has_many :tags, through: :taggings
has_many :taggings
class Post < ActiveRecord::Base
and pluralized form for :belongs_to or :has_many.
Returns the source of the through reflection. It checks both a singularized
def source_reflection through_reflection.klass._reflect_on_association(source_reflection_name) end
def source_reflection_name # :nodoc:
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 raise AmbiguousSourceReflectionForThroughAssociation.new( active_record.name, macro, name, options, source_reflection_names ) end @source_reflection_name = names.first end
def source_reflection_names
# => [:tag, :tags]
tags_reflection.source_reflection_names
tags_reflection = Post.reflect_on_association(:tags)
end
has_many :tags, through: :taggings
has_many :taggings
class Post < ActiveRecord::Base
Gets an array of possible :through source reflection names in both singular and plural form.
def source_reflection_names options[:source] ? [options[:source]] : [name.to_s.singularize, name].uniq end
def through_options
def through_options through_reflection.options end
def through_reflection
# =>
tags_reflection.through_reflection
tags_reflection = Post.reflect_on_association(:tags)
end
has_many :tags, through: :taggings
has_many :taggings
class Post < ActiveRecord::Base
of a HasManyThrough or HasOneThrough association.
Returns the AssociationReflection object specified in the :through option
def through_reflection active_record._reflect_on_association(options[:through]) end
def through_reflection?
def through_reflection? true end