aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew White <andyw@pixeltrix.co.uk>2010-03-31 02:33:04 +0100
committerwycats <wycats@gmail.com>2010-04-12 21:31:20 -0700
commit9cea9bc7f0c104095dddc036bea7f6ecb9590075 (patch)
tree612e9c686756164fa5fedb71985f6105624137f4
parentee04aea3ec1461368a72db525b325846e29b0045 (diff)
downloadrails-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-xactiverecord/lib/active_record/base.rb35
-rwxr-xr-xactiverecord/test/cases/base_test.rb8
-rw-r--r--activerecord/test/cases/modules_test.rb33
-rw-r--r--activerecord/test/fixtures/collections.yml3
-rw-r--r--activerecord/test/fixtures/products.yml4
-rw-r--r--activerecord/test/fixtures/variants.yml4
-rw-r--r--activerecord/test/models/shop.rb12
-rw-r--r--activerecord/test/schema/schema.rb14
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