Changeset 7510
- Timestamp:
- 09/18/07 10:04:11 (2 years ago)
- Files:
-
- trunk/activerecord/CHANGELOG (modified) (1 diff)
- trunk/activerecord/lib/active_record/base.rb (modified) (3 diffs)
- trunk/activerecord/test/finder_test.rb (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/activerecord/CHANGELOG
r7509 r7510 1 1 *SVN* 2 3 * Define dynamic finders as real methods after first usage. [bscofield] 2 4 3 5 * Deprecation: remove deprecated threaded_connections methods. Use allow_concurrency instead. [Jeremy Kemper] trunk/activerecord/lib/active_record/base.rb
r7509 r7510 1221 1221 # This also enables you to initialize a record if it is not found, such as find_or_initialize_by_amount(amount) 1222 1222 # or find_or_create_by_user_and_password(user, password). 1223 # 1224 # Each dynamic finder or initializer/creator is also defined in the class after it is first invoked, so that future 1225 # attempts to use it do not run through method_missing. 1223 1226 def method_missing(method_id, *arguments) 1224 1227 if match = /^find_(all_by|by)_([_a-zA-Z]\w*)$/.match(method_id.to_s) … … 1228 1231 super unless all_attributes_exists?(attribute_names) 1229 1232 1230 attributes = construct_attributes_from_arguments(attribute_names, arguments) 1231 1232 case extra_options = arguments[attribute_names.size] 1233 when nil 1234 options = { :conditions => attributes } 1233 self.class_eval %{ 1234 def self.#{method_id}(*args) 1235 options = args.last.is_a?(Hash) ? args.pop : {} 1236 attributes = construct_attributes_from_arguments([:#{attribute_names.join(',:')}], args) 1237 finder_options = { :conditions => attributes } 1238 validate_find_options(options) 1235 1239 set_readonly_option!(options) 1236 ActiveSupport::Deprecation.silence { send(finder, options) } 1237 1238 when Hash 1239 finder_options = extra_options.merge(:conditions => attributes) 1240 validate_find_options(finder_options) 1241 set_readonly_option!(finder_options) 1242 1243 if extra_options[:conditions] 1244 with_scope(:find => { :conditions => extra_options[:conditions] }) do 1245 ActiveSupport::Deprecation.silence { send(finder, finder_options) } 1240 1241 if options[:conditions] 1242 with_scope(:find => finder_options) do 1243 ActiveSupport::Deprecation.silence { send(:#{finder}, options) } 1246 1244 end 1247 1245 else 1248 ActiveSupport::Deprecation.silence { send( finder, finder_options) }1246 ActiveSupport::Deprecation.silence { send(:#{finder}, options.merge(finder_options)) } 1249 1247 end 1250 1251 else 1252 raise ArgumentError, "Unrecognized arguments for #{method_id}: #{extra_options.inspect}" 1253 end 1248 end 1249 } 1250 send(method_id, *arguments) 1254 1251 elsif match = /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/.match(method_id.to_s) 1255 1252 instantiator = determine_instantiator(match) … … 1257 1254 super unless all_attributes_exists?(attribute_names) 1258 1255 1259 if arguments[0].is_a?(Hash) 1260 attributes = arguments[0].with_indifferent_access 1261 find_attributes = attributes.slice(*attribute_names) 1262 else 1263 find_attributes = attributes = construct_attributes_from_arguments(attribute_names, arguments) 1264 end 1265 options = { :conditions => find_attributes } 1266 set_readonly_option!(options) 1267 1268 find_initial(options) || send(instantiator, attributes) 1256 self.class_eval %{ 1257 def self.#{method_id}(*args) 1258 if args[0].is_a?(Hash) 1259 attributes = args[0].with_indifferent_access 1260 find_attributes = attributes.slice(*[:#{attribute_names.join(',:')}]) 1261 else 1262 find_attributes = attributes = construct_attributes_from_arguments([:#{attribute_names.join(',:')}], args) 1263 end 1264 1265 options = { :conditions => find_attributes } 1266 set_readonly_option!(options) 1267 1268 find_initial(options) || send(:#{instantiator}, attributes) 1269 end 1270 } 1271 send(method_id, *arguments) 1269 1272 else 1270 1273 super trunk/activerecord/test/finder_test.rb
r7497 r7510 325 325 assert_nil Topic.find_by_title("The First Topic!") 326 326 end 327 328 def test_find_by_one_attribute_caches_dynamic_finder 329 # ensure this test can run independently of order 330 class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.respond_to?(:find_by_title) 331 assert !Topic.respond_to?(:find_by_title) 332 t = Topic.find_by_title("The First Topic") 333 assert Topic.respond_to?(:find_by_title) 334 end 335 336 def test_dynamic_finder_returns_same_results_after_caching 337 # ensure this test can run independently of order 338 class << Topic; self; end.send(:remove_method, :find_by_title) if Topic.respond_to?(:find_by_title) 339 t = Topic.find_by_title("The First Topic") 340 assert_equal t, Topic.find_by_title("The First Topic") # find_by_title has been cached 341 end 327 342 328 343 def test_find_by_one_attribute_with_order_option … … 333 348 def test_find_by_one_attribute_with_conditions 334 349 assert_equal accounts(:rails_core_account), Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6]) 350 end 351 352 def test_dynamic_finder_on_one_attribute_with_conditions_caches_method 353 # ensure this test can run independently of order 354 class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.respond_to?(:find_by_credit_limit) 355 assert !Account.respond_to?(:find_by_credit_limit) 356 a = Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6]) 357 assert Account.respond_to?(:find_by_credit_limit) 358 end 359 360 def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching 361 # ensure this test can run independently of order 362 class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.respond_to?(:find_by_credit_limit) 363 a = Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6]) 364 assert_equal a, Account.find_by_credit_limit(50, :conditions => ['firm_id = ?', 6]) # find_by_credit_limit has been cached 335 365 end 336 366 … … 441 471 end 442 472 473 def test_dynamic_find_or_initialize_from_one_attribute_caches_method 474 class << Company; self; end.send(:remove_method, :find_or_initialize_by_name) if Company.respond_to?(:find_or_initialize_by_name) 475 assert !Company.respond_to?(:find_or_initialize_by_name) 476 sig38 = Company.find_or_initialize_by_name("38signals") 477 assert Company.respond_to?(:find_or_initialize_by_name) 478 end 479 443 480 def test_find_or_initialize_from_two_attributes 444 481 another = Topic.find_or_initialize_by_title_and_author_name("Another topic","John") … … 463 500 assert_raises(ArgumentError) { Topic.find :first, :join => "It should be `joins'" } 464 501 assert_raises(ArgumentError) { Topic.find :first, :conditions => '1 = 1', :join => "It should be `joins'" } 502 end 503 504 def test_dynamic_finder_with_invalid_params 505 assert_raises(ArgumentError) { Topic.find_by_title 'No Title', :join => "It should be `joins'" } 465 506 end 466 507