diff options
Diffstat (limited to 'activerecord/lib/active_record/reflection.rb')
-rw-r--r-- | activerecord/lib/active_record/reflection.rb | 135 |
1 files changed, 82 insertions, 53 deletions
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index a1b498eceb..dbff4f24d6 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -13,14 +13,15 @@ module ActiveRecord def create_reflection(macro, name, options, active_record) case macro when :has_many, :belongs_to, :has_one, :has_and_belongs_to_many - reflection = AssociationReflection.new(macro, name, options, active_record) + klass = options[:through] ? ThroughReflection : AssociationReflection + reflection = klass.new(macro, name, options, active_record) when :composed_of reflection = AggregateReflection.new(macro, name, options, active_record) end write_inheritable_hash :reflections, name => reflection reflection end - + # Returns a hash containing all AssociationReflection objects for the current class # Example: # @@ -30,7 +31,7 @@ module ActiveRecord def reflections read_inheritable_attribute(:reflections) || write_inheritable_attribute(:reflections, {}) end - + # Returns an array of AggregateReflection objects for all the aggregations in the class. def reflect_on_all_aggregations reflections.values.select { |reflection| reflection.is_a?(AggregateReflection) } @@ -116,6 +117,11 @@ module ActiveRecord @sanitized_conditions ||= klass.send(:sanitize_sql, options[:conditions]) if options[:conditions] end + # Returns +true+ if +self+ is a +belongs_to+ reflection. + def belongs_to? + macro == :belongs_to + end + private def derive_class_name name.to_s.camelize @@ -192,6 +198,52 @@ module ActiveRecord end end + def check_validity! + end + + def through_reflection + false + end + + def through_reflection_primary_key_name + end + + def source_reflection + nil + end + + private + def derive_class_name + class_name = name.to_s.camelize + class_name = class_name.singularize if [ :has_many, :has_and_belongs_to_many ].include?(macro) + class_name + end + + def derive_primary_key_name + if belongs_to? + "#{name}_id" + elsif options[:as] + "#{options[:as]}_id" + else + active_record.name.foreign_key + end + end + end + + # Holds all the meta-data about a :through association as it was specified in the Active Record class. + class ThroughReflection < AssociationReflection #:nodoc: + # Gets the source of the through reflection. It checks both a singularized and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>. + # (The <tt>:tags</tt> association on Tagging below.) + # + # class Post < ActiveRecord::Base + # has_many :taggings + # has_many :tags, :through => :taggings + # end + # + def source_reflection + @source_reflection ||= source_reflection_names.collect { |name| through_reflection.klass.reflect_on_association(name) }.compact.first + end + # Returns the AssociationReflection object specified in the <tt>:through</tt> option # of a HasManyThrough or HasOneThrough association. Example: # @@ -204,7 +256,7 @@ module ActiveRecord # taggings_reflection = tags_reflection.through_reflection # def through_reflection - @through_reflection ||= options[:through] ? active_record.reflect_on_association(options[:through]) : false + @through_reflection ||= active_record.reflect_on_association(options[:through]) end # Gets an array of possible <tt>:through</tt> source reflection names: @@ -215,63 +267,40 @@ module ActiveRecord @source_reflection_names ||= (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym } end - # Gets the source of the through reflection. It checks both a singularized and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>. - # (The <tt>:tags</tt> association on Tagging below.) - # - # class Post < ActiveRecord::Base - # has_many :taggings - # has_many :tags, :through => :taggings - # end - # - def source_reflection - return nil unless through_reflection - @source_reflection ||= source_reflection_names.collect { |name| through_reflection.klass.reflect_on_association(name) }.compact.first - end - def check_validity! - if options[:through] - if through_reflection.nil? - raise HasManyThroughAssociationNotFoundError.new(active_record.name, self) - end - - if source_reflection.nil? - raise HasManyThroughSourceAssociationNotFoundError.new(self) - end + if through_reflection.nil? + raise HasManyThroughAssociationNotFoundError.new(active_record.name, self) + end - if options[:source_type] && source_reflection.options[:polymorphic].nil? - raise HasManyThroughAssociationPointlessSourceTypeError.new(active_record.name, self, source_reflection) - end - - if source_reflection.options[:polymorphic] && options[:source_type].nil? - raise HasManyThroughAssociationPolymorphicError.new(active_record.name, self, source_reflection) - end - - unless [:belongs_to, :has_many].include?(source_reflection.macro) && source_reflection.options[:through].nil? - raise HasManyThroughSourceAssociationMacroError.new(self) - end + if source_reflection.nil? + raise HasManyThroughSourceAssociationNotFoundError.new(self) + end + + if options[:source_type] && source_reflection.options[:polymorphic].nil? + raise HasManyThroughAssociationPointlessSourceTypeError.new(active_record.name, self, source_reflection) end + + if source_reflection.options[:polymorphic] && options[:source_type].nil? + raise HasManyThroughAssociationPolymorphicError.new(active_record.name, self, source_reflection) + end + + unless [:belongs_to, :has_many].include?(source_reflection.macro) && source_reflection.options[:through].nil? + raise HasManyThroughSourceAssociationMacroError.new(self) + end + end + + def through_reflection_primary_key + through_reflection.belongs_to? ? through_reflection.klass.primary_key : through_reflection.primary_key_name + end + + def through_reflection_primary_key_name + through_reflection.primary_key_name if through_reflection.belongs_to? end private def derive_class_name # get the class_name of the belongs_to association of the through reflection - if through_reflection - options[:source_type] || source_reflection.class_name - else - class_name = name.to_s.camelize - class_name = class_name.singularize if [ :has_many, :has_and_belongs_to_many ].include?(macro) - class_name - end - end - - def derive_primary_key_name - if macro == :belongs_to - "#{name}_id" - elsif options[:as] - "#{options[:as]}_id" - else - active_record.name.foreign_key - end + options[:source_type] || source_reflection.class_name end end end |