diff options
author | Andrew White <andyw@pixeltrix.co.uk> | 2010-03-31 02:33:04 +0100 |
---|---|---|
committer | wycats <wycats@gmail.com> | 2010-04-12 21:31:20 -0700 |
commit | 9cea9bc7f0c104095dddc036bea7f6ecb9590075 (patch) | |
tree | 612e9c686756164fa5fedb71985f6105624137f4 | |
parent | ee04aea3ec1461368a72db525b325846e29b0045 (diff) | |
download | rails-9cea9bc7f0c104095dddc036bea7f6ecb9590075.tar.gz rails-9cea9bc7f0c104095dddc036bea7f6ecb9590075.tar.bz2 rails-9cea9bc7f0c104095dddc036bea7f6ecb9590075.zip |
Refactor compute_type to handle situations where the correct class is already loaded
Signed-off-by: wycats <wycats@gmail.com>
-rwxr-xr-x | activerecord/lib/active_record/base.rb | 35 | ||||
-rwxr-xr-x | activerecord/test/cases/base_test.rb | 8 | ||||
-rw-r--r-- | activerecord/test/cases/modules_test.rb | 33 | ||||
-rw-r--r-- | activerecord/test/fixtures/collections.yml | 3 | ||||
-rw-r--r-- | activerecord/test/fixtures/products.yml | 4 | ||||
-rw-r--r-- | activerecord/test/fixtures/variants.yml | 4 | ||||
-rw-r--r-- | activerecord/test/models/shop.rb | 12 | ||||
-rw-r--r-- | activerecord/test/schema/schema.rb | 14 |
8 files changed, 88 insertions, 25 deletions
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index e60e990cd6..d7683a9a16 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1080,16 +1080,6 @@ module ActiveRecord #:nodoc: end end - # Nest the type name in the same module as this class. - # Bar is "MyApp::Business::Bar" relative to MyApp::Business::Foo - def type_name_with_module(type_name) - if store_full_sti_class - type_name - else - (/^::/ =~ type_name) ? type_name : "#{parent.name}::#{type_name}" - end - end - def construct_finder_arel(options = {}, scope = nil) relation = options.is_a?(Hash) ? unscoped.apply_finder_options(options) : unscoped.merge(options) relation = scope.merge(relation) if scope @@ -1316,13 +1306,26 @@ module ActiveRecord #:nodoc: # Returns the class type of the record using the current module as a prefix. So descendants of # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass. def compute_type(type_name) - modularized_name = type_name_with_module(type_name) - silence_warnings do - begin - class_eval(modularized_name, __FILE__) - rescue NameError - class_eval(type_name, __FILE__) + if type_name.match(/^::/) + # If the type is prefixed with a scope operator then we assume that + # the type_name is an absolute reference. + type_name.constantize + else + # Build a list of candidates to search for + candidates = [] + name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" } + candidates << type_name + + candidates.each do |candidate| + begin + constant = candidate.constantize + return constant if candidate == constant.to_s + rescue NameError + rescue ArgumentError + end end + + raise NameError, "uninitialized constant #{candidates.first}" end end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 8bff13aa96..1c3655b587 100755 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -2205,14 +2205,6 @@ class BasicsTest < ActiveRecord::TestCase assert xml.include?(%(<arbitrary-element>#{value}</arbitrary-element>)) end - def test_type_name_with_module_should_handle_beginning - ActiveRecord::Base.store_full_sti_class = false - assert_equal 'ActiveRecord::Person', ActiveRecord::Base.send(:type_name_with_module, 'Person') - assert_equal '::Person', ActiveRecord::Base.send(:type_name_with_module, '::Person') - ensure - ActiveRecord::Base.store_full_sti_class = true - end - def test_to_param_should_return_string assert_kind_of String, Client.find(:first).to_param end diff --git a/activerecord/test/cases/modules_test.rb b/activerecord/test/cases/modules_test.rb index 7209966bf8..c924c3dfad 100644 --- a/activerecord/test/cases/modules_test.rb +++ b/activerecord/test/cases/modules_test.rb @@ -1,8 +1,9 @@ require "cases/helper" require 'models/company_in_module' +require 'models/shop' class ModulesTest < ActiveRecord::TestCase - fixtures :accounts, :companies, :projects, :developers + fixtures :accounts, :companies, :projects, :developers, :collections, :products, :variants def setup # need to make sure Object::Firm and Object::Client are not defined, @@ -110,4 +111,34 @@ class ModulesTest < ActiveRecord::TestCase ActiveRecord::Base.table_name_prefix = '' classes.each(&:reset_table_name) end + + def test_compute_type_can_infer_class_name_of_sibling_inside_module + old = ActiveRecord::Base.store_full_sti_class + ActiveRecord::Base.store_full_sti_class = true + assert_equal MyApplication::Business::Firm, MyApplication::Business::Client.send(:compute_type, "Firm") + ensure + ActiveRecord::Base.store_full_sti_class = old + end + + def test_nested_models_should_not_raise_exception_when_using_delete_all_dependency_on_association + old = ActiveRecord::Base.store_full_sti_class + ActiveRecord::Base.store_full_sti_class = true + + collection = Shop::Collection.find(:first) + assert !collection.products.empty?, "Collection should have products" + assert_nothing_raised { collection.destroy } + ensure + ActiveRecord::Base.store_full_sti_class = old + end + + def test_nested_models_should_not_raise_exception_when_using_nullify_dependency_on_association + old = ActiveRecord::Base.store_full_sti_class + ActiveRecord::Base.store_full_sti_class = true + + product = Shop::Product.find(:first) + assert !product.variants.empty?, "Product should have variants" + assert_nothing_raised { product.destroy } + ensure + ActiveRecord::Base.store_full_sti_class = old + end end diff --git a/activerecord/test/fixtures/collections.yml b/activerecord/test/fixtures/collections.yml new file mode 100644 index 0000000000..ad0fd26554 --- /dev/null +++ b/activerecord/test/fixtures/collections.yml @@ -0,0 +1,3 @@ +collection_1: + id: 1 + name: Collection diff --git a/activerecord/test/fixtures/products.yml b/activerecord/test/fixtures/products.yml new file mode 100644 index 0000000000..8a197fb038 --- /dev/null +++ b/activerecord/test/fixtures/products.yml @@ -0,0 +1,4 @@ +product_1: + id: 1 + collection_id: 1 + name: Product diff --git a/activerecord/test/fixtures/variants.yml b/activerecord/test/fixtures/variants.yml new file mode 100644 index 0000000000..06be30727b --- /dev/null +++ b/activerecord/test/fixtures/variants.yml @@ -0,0 +1,4 @@ +variant_1: + id: 1 + product_id: 1 + name: Variant diff --git a/activerecord/test/models/shop.rb b/activerecord/test/models/shop.rb new file mode 100644 index 0000000000..b232185693 --- /dev/null +++ b/activerecord/test/models/shop.rb @@ -0,0 +1,12 @@ +module Shop + class Collection < ActiveRecord::Base + has_many :products, :dependent => :nullify + end + + class Product < ActiveRecord::Base + has_many :variants, :dependent => :delete_all + end + + class Variant < ActiveRecord::Base + end +end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index bec4291457..7a0cf550e0 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -99,6 +99,10 @@ ActiveRecord::Schema.define do t.string :name end + create_table :collections, :force => true do |t| + t.string :name + end + create_table :colnametests, :force => true do |t| t.integer :references, :null => false end @@ -394,6 +398,11 @@ ActiveRecord::Schema.define do t.integer :price end + create_table :products, :force => true do |t| + t.references :collection + t.string :name + end + create_table :projects, :force => true do |t| t.string :name t.string :type @@ -499,6 +508,11 @@ ActiveRecord::Schema.define do t.column :looter_type, :string end + create_table :variants, :force => true do |t| + t.references :product + t.string :name + end + create_table :vertices, :force => true do |t| t.column :label, :string end |