Skip to content
This repository
Browse code

Refactor compute_type to handle situations where the correct class is…

… already loaded

Signed-off-by: wycats <wycats@gmail.com>
  • Loading branch information...
commit 9cea9bc7f0c104095dddc036bea7f6ecb9590075 1 parent ee04aea
Andrew White authored March 31, 2010 wycats committed April 12, 2010
35  activerecord/lib/active_record/base.rb
@@ -1080,16 +1080,6 @@ def find_sti_class(type_name)
1080 1080
           end
1081 1081
         end
1082 1082
 
1083  
-        # Nest the type name in the same module as this class.
1084  
-        # Bar is "MyApp::Business::Bar" relative to MyApp::Business::Foo
1085  
-        def type_name_with_module(type_name)
1086  
-          if store_full_sti_class
1087  
-            type_name
1088  
-          else
1089  
-            (/^::/ =~ type_name) ? type_name : "#{parent.name}::#{type_name}"
1090  
-          end
1091  
-        end
1092  
-
1093 1083
         def construct_finder_arel(options = {}, scope = nil)
1094 1084
           relation = options.is_a?(Hash) ? unscoped.apply_finder_options(options) : unscoped.merge(options)
1095 1085
           relation = scope.merge(relation) if scope
@@ -1316,13 +1306,26 @@ def current_scoped_methods #:nodoc:
1316 1306
         # Returns the class type of the record using the current module as a prefix. So descendants of
1317 1307
         # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
1318 1308
         def compute_type(type_name)
1319  
-          modularized_name = type_name_with_module(type_name)
1320  
-          silence_warnings do
1321  
-            begin
1322  
-              class_eval(modularized_name, __FILE__)
1323  
-            rescue NameError
1324  
-              class_eval(type_name, __FILE__)
  1309
+          if type_name.match(/^::/)
  1310
+            # If the type is prefixed with a scope operator then we assume that
  1311
+            # the type_name is an absolute reference.
  1312
+            type_name.constantize
  1313
+          else
  1314
+            # Build a list of candidates to search for
  1315
+            candidates = []
  1316
+            name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" }
  1317
+            candidates << type_name
  1318
+
  1319
+            candidates.each do |candidate|
  1320
+              begin
  1321
+                constant = candidate.constantize
  1322
+                return constant if candidate == constant.to_s
  1323
+              rescue NameError
  1324
+              rescue ArgumentError
  1325
+              end
1325 1326
             end
  1327
+
  1328
+            raise NameError, "uninitialized constant #{candidates.first}"
1326 1329
           end
1327 1330
         end
1328 1331
 
8  activerecord/test/cases/base_test.rb
@@ -2205,14 +2205,6 @@ def test_to_xml_with_block
2205 2205
     assert xml.include?(%(<arbitrary-element>#{value}</arbitrary-element>))
2206 2206
   end
2207 2207
 
2208  
-  def test_type_name_with_module_should_handle_beginning
2209  
-    ActiveRecord::Base.store_full_sti_class = false
2210  
-    assert_equal 'ActiveRecord::Person', ActiveRecord::Base.send(:type_name_with_module, 'Person')
2211  
-    assert_equal '::Person', ActiveRecord::Base.send(:type_name_with_module, '::Person')
2212  
-  ensure
2213  
-    ActiveRecord::Base.store_full_sti_class = true
2214  
-  end
2215  
-
2216 2208
   def test_to_param_should_return_string
2217 2209
     assert_kind_of String, Client.find(:first).to_param
2218 2210
   end
33  activerecord/test/cases/modules_test.rb
... ...
@@ -1,8 +1,9 @@
1 1
 require "cases/helper"
2 2
 require 'models/company_in_module'
  3
+require 'models/shop'
3 4
 
4 5
 class ModulesTest < ActiveRecord::TestCase
5  
-  fixtures :accounts, :companies, :projects, :developers
  6
+  fixtures :accounts, :companies, :projects, :developers, :collections, :products, :variants
6 7
 
7 8
   def setup
8 9
     # need to make sure Object::Firm and Object::Client are not defined,
@@ -110,4 +111,34 @@ def test_module_table_name_prefix_with_global_prefix
110 111
     ActiveRecord::Base.table_name_prefix = ''
111 112
     classes.each(&:reset_table_name)
112 113
   end
  114
+
  115
+  def test_compute_type_can_infer_class_name_of_sibling_inside_module
  116
+    old = ActiveRecord::Base.store_full_sti_class
  117
+    ActiveRecord::Base.store_full_sti_class = true
  118
+    assert_equal MyApplication::Business::Firm, MyApplication::Business::Client.send(:compute_type, "Firm")
  119
+  ensure
  120
+    ActiveRecord::Base.store_full_sti_class = old
  121
+  end
  122
+
  123
+  def test_nested_models_should_not_raise_exception_when_using_delete_all_dependency_on_association
  124
+    old = ActiveRecord::Base.store_full_sti_class
  125
+    ActiveRecord::Base.store_full_sti_class = true
  126
+
  127
+    collection = Shop::Collection.find(:first)
  128
+    assert !collection.products.empty?, "Collection should have products"
  129
+    assert_nothing_raised { collection.destroy }
  130
+  ensure
  131
+    ActiveRecord::Base.store_full_sti_class = old
  132
+  end
  133
+
  134
+  def test_nested_models_should_not_raise_exception_when_using_nullify_dependency_on_association
  135
+    old = ActiveRecord::Base.store_full_sti_class
  136
+    ActiveRecord::Base.store_full_sti_class = true
  137
+
  138
+    product = Shop::Product.find(:first)
  139
+    assert !product.variants.empty?, "Product should have variants"
  140
+    assert_nothing_raised { product.destroy }
  141
+  ensure
  142
+    ActiveRecord::Base.store_full_sti_class = old
  143
+  end
113 144
 end
3  activerecord/test/fixtures/collections.yml
... ...
@@ -0,0 +1,3 @@
  1
+collection_1:
  2
+  id: 1
  3
+  name: Collection
4  activerecord/test/fixtures/products.yml
... ...
@@ -0,0 +1,4 @@
  1
+product_1:
  2
+  id: 1
  3
+  collection_id: 1
  4
+  name: Product
4  activerecord/test/fixtures/variants.yml
... ...
@@ -0,0 +1,4 @@
  1
+variant_1:
  2
+  id: 1
  3
+  product_id: 1
  4
+  name: Variant
12  activerecord/test/models/shop.rb
... ...
@@ -0,0 +1,12 @@
  1
+module Shop
  2
+  class Collection < ActiveRecord::Base
  3
+    has_many :products, :dependent => :nullify
  4
+  end
  5
+
  6
+  class Product < ActiveRecord::Base
  7
+    has_many :variants, :dependent => :delete_all
  8
+  end
  9
+  
  10
+  class Variant < ActiveRecord::Base
  11
+  end
  12
+end
14  activerecord/test/schema/schema.rb
@@ -99,6 +99,10 @@ def create_table(*args, &block)
99 99
     t.string :name
100 100
   end
101 101
 
  102
+  create_table :collections, :force => true do |t|
  103
+    t.string :name
  104
+  end
  105
+
102 106
   create_table :colnametests, :force => true do |t|
103 107
     t.integer :references, :null => false
104 108
   end
@@ -394,6 +398,11 @@ def create_table(*args, &block)
394 398
     t.integer :price
395 399
   end
396 400
 
  401
+  create_table :products, :force => true do |t|
  402
+    t.references :collection
  403
+    t.string     :name
  404
+  end
  405
+
397 406
   create_table :projects, :force => true do |t|
398 407
     t.string :name
399 408
     t.string :type
@@ -499,6 +508,11 @@ def create_table(*args, &block)
499 508
     t.column :looter_type, :string
500 509
   end
501 510
 
  511
+  create_table :variants, :force => true do |t|
  512
+    t.references :product
  513
+    t.string     :name
  514
+  end
  515
+
502 516
   create_table :vertices, :force => true do |t|
503 517
     t.column :label, :string
504 518
   end

0 notes on commit 9cea9bc

Please sign in to comment.
Something went wrong with that request. Please try again.