diff options
author | Jason Rush <diminish7@gmail.com> | 2012-04-05 13:21:48 -0600 |
---|---|---|
committer | Andrew White <andyw@pixeltrix.co.uk> | 2012-11-29 05:50:34 +0000 |
commit | 89b5b31cc4f8407f648a2447665ef23f9024e8a5 (patch) | |
tree | 721b47a8f33bf70851736164bf4a80cdd7c59e94 /activerecord/lib | |
parent | eba430aecbce963f5b2d91ef6a9c36aec8c824bb (diff) | |
download | rails-89b5b31cc4f8407f648a2447665ef23f9024e8a5.tar.gz rails-89b5b31cc4f8407f648a2447665ef23f9024e8a5.tar.bz2 rails-89b5b31cc4f8407f648a2447665ef23f9024e8a5.zip |
Added STI support to init and building associations
Allows you to do BaseClass.new(:type => "SubClass") as well as
parent.children.build(:type => "SubClass") or parent.build_child
to initialize an STI subclass. Ensures that the class name is a
valid class and that it is in the ancestors of the super class
that the association is expecting.
Diffstat (limited to 'activerecord/lib')
-rw-r--r-- | activerecord/lib/active_record/base.rb | 1 | ||||
-rw-r--r-- | activerecord/lib/active_record/inheritance.rb | 26 | ||||
-rw-r--r-- | activerecord/lib/active_record/reflection.rb | 2 |
3 files changed, 28 insertions, 1 deletions
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 965fe3f33a..aab832c2f7 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -13,6 +13,7 @@ require 'active_support/core_ext/string/behavior' require 'active_support/core_ext/kernel/singleton_class' require 'active_support/core_ext/module/introspection' require 'active_support/core_ext/object/duplicable' +require 'active_support/core_ext/class/subclasses' require 'arel' require 'active_record/errors' require 'active_record/log_subscriber' diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb index a448fa1f5c..850911ebe7 100644 --- a/activerecord/lib/active_record/inheritance.rb +++ b/activerecord/lib/active_record/inheritance.rb @@ -9,6 +9,19 @@ module ActiveRecord end module ClassMethods + # Determines if one of the attributes passed in is the inheritance column, + # and if the inheritance column is attr accessible, it initializes an + # instance of the given subclass instead of the base class + def new(*args, &block) + if (attrs = args.first).is_a?(Hash) + if subclass = subclass_from_attrs(attrs) + return subclass.new(*args, &block) + end + end + # Delegate to the original .new + super + end + # True if this isn't a concrete subclass needing a STI type condition. def descends_from_active_record? if self == Base @@ -145,6 +158,19 @@ module ActiveRecord sti_column.in(sti_names) end + + # Detect the subclass from the inheritance column of attrs. If the inheritance column value + # is not self or a valid subclass, raises ActiveRecord::SubclassNotFound + # If this is a StrongParameters hash, and access to inheritance_column is not permitted, + # this will ignore the inheritance column and return nil + def subclass_from_attrs(attrs) + subclass_name = attrs.with_indifferent_access[inheritance_column] + return nil if subclass_name.blank? || subclass_name == self.name + unless subclass = subclasses.detect { |sub| sub.name == subclass_name } + raise ActiveRecord::SubclassNotFound.new("Invalid single-table inheritance type: #{subclass_name} is not a subclass of #{name}") + end + subclass + end end private diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 0103de4cbd..bcfcb061f2 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -179,7 +179,7 @@ module ActiveRecord @collection = [:has_many, :has_and_belongs_to_many].include?(macro) end - # Returns a new, unsaved instance of the associated class. +options+ will + # Returns a new, unsaved instance of the associated class. +attributes+ will # be passed to the class's constructor. def build_association(attributes, &block) klass.new(attributes, &block) |