From a7b925800f2df2ece736f1d9d34cd159cd72fb93 Mon Sep 17 00:00:00 2001 From: Rodrigo Kochenburger Date: Fri, 11 Apr 2008 12:35:09 -0300 Subject: [PATCH] Add ActiveRecord option to store the full class name on STI's type column, allowing one to have STI subclasses in different namespaces --- activerecord/lib/active_record/base.rb | 10 ++++++-- activerecord/test/cases/inheritance_test.rb | 21 ++++++++++++++++++++ activerecord/test/models/collection_item.rb | 7 ++++++ activerecord/test/schema/schema.rb | 6 +++++ .../configs/initializers/new_rails_defaults.rb | 3 ++ 5 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 activerecord/test/models/collection_item.rb diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 8bef5ed..bac80d0 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -436,6 +436,10 @@ module ActiveRecord #:nodoc: cattr_accessor :schema_format , :instance_writer => false @@schema_format = :ruby + # Determine whether to store the full constant name including namespace when using STI + superclass_delegating_accessor :store_full_sti_class + self.store_full_sti_class = false + class << self # Class methods # Find operates with four different retrieval approaches: # @@ -1548,8 +1552,8 @@ module ActiveRecord #:nodoc: def type_condition quoted_inheritance_column = connection.quote_column_name(inheritance_column) - type_condition = subclasses.inject("#{quoted_table_name}.#{quoted_inheritance_column} = '#{name.demodulize}' ") do |condition, subclass| - condition << "OR #{quoted_table_name}.#{quoted_inheritance_column} = '#{subclass.name.demodulize}' " + type_condition = subclasses.inject("#{quoted_table_name}.#{quoted_inheritance_column} = '#{store_full_sti_class ? name : name.demodulize}' ") do |condition, subclass| + condition << "OR #{quoted_table_name}.#{quoted_inheritance_column} = '#{store_full_sti_class ? subclass.name : subclass.name.demodulize}' " end " (#{type_condition}) " @@ -2468,7 +2472,7 @@ module ActiveRecord #:nodoc: # Message class in that example. def ensure_proper_type unless self.class.descends_from_active_record? - write_attribute(self.class.inheritance_column, Inflector.demodulize(self.class.name)) + write_attribute(self.class.inheritance_column, store_full_sti_class ? self.class.name : Inflector.demodulize(self.class.name)) end end diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index c9eb83e..71848de 100755 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -2,9 +2,30 @@ require "cases/helper" require 'models/company' require 'models/project' require 'models/subscriber' +require 'models/collection_item' class InheritanceTest < ActiveRecord::TestCase fixtures :companies, :projects, :subscribers, :accounts + + def test_should_store_demodulized_class_name_with_store_full_sti_class_option_disabled + item = ComicCollection::Item.new + assert_equal 'Item', item[:type] + end + + def test_should_store_full_class_name_with_store_full_sti_class_option_enabled + ActiveRecord::Base.store_full_sti_class = true + item = ComicCollection::Item.new + assert_equal 'ComicCollection::Item', item[:type] + ActiveRecord::Base.store_full_sti_class = false + end + + def test_different_namespace_subclass_should_load_correctly_with_store_full_sti_class_option + ActiveRecord::Base.store_full_sti_class = true + item = ComicCollection::Item.create :name => "Wolverine 2" + assert_not_nil CollectionItem.find(item.id) + assert_not_nil ComicCollection::Item.find(item.id) + ActiveRecord::Base.store_full_sti_class = false + end def test_company_descends_from_active_record assert_raise(NoMethodError) { ActiveRecord::Base.descends_from_active_record? } diff --git a/activerecord/test/models/collection_item.rb b/activerecord/test/models/collection_item.rb new file mode 100644 index 0000000..2735993 --- /dev/null +++ b/activerecord/test/models/collection_item.rb @@ -0,0 +1,7 @@ +class CollectionItem < ActiveRecord::Base +end + +module ComicCollection + class Item < CollectionItem + end +end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 856f2fd..ca6c503 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -424,4 +424,10 @@ ActiveRecord::Schema.define do t.integer :sponsorable_id t.string :sponsorable_type end + + + create_table :collection_items, :force => true do |t| + t.string :name + t.string :type + end end diff --git a/railties/configs/initializers/new_rails_defaults.rb b/railties/configs/initializers/new_rails_defaults.rb index 3a617e3..b8f0e2c 100644 --- a/railties/configs/initializers/new_rails_defaults.rb +++ b/railties/configs/initializers/new_rails_defaults.rb @@ -7,6 +7,9 @@ ActiveRecord::Base.partial_updates = true # Include ActiveRecord class name as root for JSON serialized output. ActiveRecord::Base.include_root_in_json = true +# Store the full class name (including module namespace) in STI type column +ActiveRecord::Base.store_full_sti_class = true + # Use ISO 8601 format for JSON serialized times and dates ActiveSupport.use_standard_json_time_format = true -- 1.5.4.5