diff options
Diffstat (limited to 'activerecord/lib/active_record/reflection.rb')
-rw-r--r-- | activerecord/lib/active_record/reflection.rb | 75 |
1 files changed, 43 insertions, 32 deletions
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 8a9488656b..f47282b7fd 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -10,6 +10,27 @@ module ActiveRecord self.aggregate_reflections = {} end + def self.create(macro, name, scope, options, ar) + case macro + when :has_and_belongs_to_many + klass = AssociationReflection + when :has_many, :belongs_to, :has_one + klass = options[:through] ? ThroughReflection : AssociationReflection + when :composed_of + klass = AggregateReflection + end + + klass.new(macro, name, scope, options, ar) + end + + def self.add_reflection(ar, name, reflection) + ar.reflections = ar.reflections.merge(name => reflection) + end + + def self.add_aggregate_reflection(ar, name, reflection) + ar.aggregate_reflections = ar.aggregate_reflections.merge(name => reflection) + end + # \Reflection enables to interrogate Active Record classes and objects # about their associations and aggregations. This information can, # for example, be used in a form builder that takes an Active Record object @@ -19,25 +40,6 @@ module ActiveRecord # MacroReflection class has info for AggregateReflection and AssociationReflection # classes. module ClassMethods - def create_reflection(macro, name, scope, options, active_record) - case macro - when :has_many, :belongs_to, :has_one, :has_and_belongs_to_many - klass = options[:through] ? ThroughReflection : AssociationReflection - when :composed_of - klass = AggregateReflection - end - - reflection = klass.new(macro, name, scope, options, active_record) - - if klass == AggregateReflection - self.aggregate_reflections = self.aggregate_reflections.merge(name => reflection) - else - self.reflections = self.reflections.merge(name => reflection) - end - - reflection - end - # Returns an array of AggregateReflection objects for all the aggregations in the class. def reflect_on_all_aggregations aggregate_reflections.values @@ -119,6 +121,7 @@ module ActiveRecord @scope = scope @options = options @active_record = active_record + @klass = options[:class] @plural_name = active_record.pluralize_table_names ? name.to_s.pluralize : name.to_s end @@ -191,7 +194,7 @@ module ActiveRecord attr_reader :type, :foreign_type - def initialize(*args) + def initialize(macro, name, scope, options, active_record) super @collection = [:has_many, :has_and_belongs_to_many].include?(macro) @automatic_inverse_of = nil @@ -267,7 +270,7 @@ module ActiveRecord end def source_reflection - nil + self end # A chain of reflections from this one back to the owner. For more see the explanation in @@ -369,6 +372,12 @@ module ActiveRecord VALID_AUTOMATIC_INVERSE_MACROS = [:has_many, :has_one, :belongs_to] INVALID_AUTOMATIC_INVERSE_OPTIONS = [:conditions, :through, :polymorphic, :foreign_key] + protected + + def actual_source_reflection # FIXME: this is a horrible name + self + end + private # Attempts to find the inverse association name automatically. # If it cannot find a suitable inverse association name, it returns @@ -386,7 +395,7 @@ module ActiveRecord # returns either nil or the inverse association name that it finds. def automatic_inverse_of if can_find_inverse_of_automatically?(self) - inverse_name = active_record.name.downcase.to_sym + inverse_name = ActiveSupport::Inflector.underscore(active_record.name).to_sym begin reflection = klass.reflect_on_association(inverse_name) @@ -405,7 +414,7 @@ module ActiveRecord end # Checks if the inverse reflection that is returned from the - # +set_automatic_inverse_of+ method is a valid reflection. We must + # +automatic_inverse_of+ method is a valid reflection. We must # make sure that the reflection's active_record name matches up # with the current reflection's klass name. # @@ -414,7 +423,6 @@ module ActiveRecord def valid_inverse_reflection?(reflection) reflection && klass.name == reflection.active_record.name && - klass.primary_key == reflection.active_record_primary_key && can_find_inverse_of_automatically?(reflection) end @@ -527,7 +535,9 @@ module ActiveRecord # def chain @chain ||= begin - chain = source_reflection.chain + through_reflection.chain + 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 @@ -578,7 +588,7 @@ module ActiveRecord # A through association is nested if there would be more than one join table def nested? - chain.length > 2 || through_reflection.macro == :has_and_belongs_to_many + chain.length > 2 || through_reflection.has_and_belongs_to_many? end # We want to use the klass from this reflection, rather than just delegate straight to @@ -587,12 +597,7 @@ module ActiveRecord def association_primary_key(klass = nil) # Get the "actual" source reflection if the immediate source reflection has a # source reflection itself - source_reflection = self.source_reflection - while source_reflection.source_reflection - source_reflection = source_reflection.source_reflection - end - - source_reflection.options[:primary_key] || primary_key(klass || self.klass) + actual_source_reflection.options[:primary_key] || primary_key(klass || self.klass) end # Gets an array of possible <tt>:through</tt> source reflection names in both singular and plural form. @@ -671,6 +676,12 @@ directive on your declaration like: check_validity_of_inverse! end + protected + + def actual_source_reflection # FIXME: this is a horrible name + source_reflection.actual_source_reflection + end + private def derive_class_name # get the class_name of the belongs_to association of the through reflection |