Changeset 504
- Timestamp:
- 01/25/05 12:45:01 (4 years ago)
- Files:
-
- trunk/activerecord/CHANGELOG (modified) (1 diff)
- trunk/activerecord/lib/active_record/associations/association_collection.rb (modified) (1 diff)
- trunk/activerecord/lib/active_record/associations/has_many_association.rb (modified) (1 diff)
- trunk/activerecord/lib/active_record/base.rb (modified) (3 diffs)
- trunk/activerecord/test/associations_test.rb (modified) (2 diffs)
- trunk/activerecord/test/base_test.rb (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/activerecord/CHANGELOG
r498 r504 1 1 *SVN* 2 2 3 * Added Base.update_collection that can update an array of id/attribute pairs, such as the ones produced by the recent added support for automatic id-based indexing for lists of items #526 [Duane Johnson] 3 * Added that has_many association build and create methods can take arrays of record data like Base#create and Base#build to build/create multiple records at once. 4 5 * Added that Base#delete and Base#destroy both can take an array of ids to delete/destroy #336 6 7 * Added the option of supplying an array of attributes to Base#create, so that multiple records can be created at once. 8 9 * Added the option of supplying an array of ids and attributes to Base#update, so that multiple records can be updated at once (inspired by #526/Duane Johnson). Example 10 11 people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy"} } 12 Person.update(people.keys, people.values) 4 13 5 14 * Added ActiveRecord::Base.timestamps_gmt that can be set to true to make the automated timestamping use GMT instead of local time #520 [Scott Baron] trunk/activerecord/lib/active_record/associations/association_collection.rb
r456 r504 54 54 def create(attributes = {}) 55 55 # Can't use Base.create since the foreign key may be a protected attribute. 56 record = build(attributes) 57 record.save unless @owner.new_record? 58 record 56 if attributes.is_a?(Array) 57 attributes.collect { |attr| create(attr) } 58 else 59 record = build(attributes) 60 record.save unless @owner.new_record? 61 record 62 end 59 63 end 60 64 trunk/activerecord/lib/active_record/associations/has_many_association.rb
r464 r504 10 10 11 11 def build(attributes = {}) 12 load_target 13 record = @association_class.new(attributes) 14 record[@association_class_primary_key_name] = @owner.id unless @owner.new_record? 15 @target << record 16 record 12 if attributes.is_a?(Array) 13 attributes.collect { |attr| create(attr) } 14 else 15 load_target 16 record = @association_class.new(attributes) 17 record[@association_class_primary_key_name] = @owner.id unless @owner.new_record? 18 @target << record 19 record 20 end 17 21 end 18 22 trunk/activerecord/lib/active_record/base.rb
r496 r504 341 341 # fail under validations, the unsaved object is still returned. 342 342 def create(attributes = nil) 343 object = new(attributes) 344 object.save 345 object 343 if attributes.is_a?(Array) 344 attributes.collect { |attr| create(attr) } 345 else 346 object = new(attributes) 347 object.save 348 object 349 end 346 350 end 347 351 … … 349 353 # and returns it. If the save fail under validations, the unsaved object is still returned. 350 354 def update(id, attributes) 351 object = find(id) 352 object.attributes = attributes 353 object.save 354 object 355 end 356 357 # Deletes the record with the given +id+ without instantiating an object first. 355 if id.is_a?(Array) 356 idx = -1 357 id.collect { |id| idx += 1; update(id, attributes[idx]) } 358 else 359 object = find(id) 360 object.update_attributes(attributes) 361 object 362 end 363 end 364 365 # Deletes the record with the given +id+ without instantiating an object first. If an array of ids is provided, all of them 366 # are deleted. 358 367 def delete(id) 359 delete_all([ "#{primary_key} = ?", id ])368 delete_all([ "#{primary_key} IN (?)", id ]) 360 369 end 361 370 362 371 # Destroys the record with the given +id+ by instantiating the object and calling #destroy (all the callbacks are the triggered). 372 # If an array of ids is provided, all of them are destroyed. 363 373 def destroy(id) 364 find(id).destroy374 id.is_a?(Array) ? id.each { |id| destroy(id) } : find(id).destroy 365 375 end 366 376 … … 374 384 end 375 385 376 # Updates several records at a time using the pattern of a hash that contains id => {attributes} pairs as contained in +id_and_attributes_pairs+.377 # If there are certain conditions that must be met in order for the update to occur, an optional block378 # containing a conditional statement may be used. Example:379 # Person.update_collection { 23 => { "first_name" => "John", "last_name" => "Peterson" },380 # 25 => { "first_name" => "Duane", "last_name" => "Johnson" } }381 #382 # # Updates only those records whose first name begins with 'duane' or 'Duane'383 # Person.update_collection @params['people'] do |activerecord_object, new_attributes|384 # activerecord_object.first_name =~ /^[dD]uane.*/385 # end386 #387 # The conditional block may also be of use when you have more than one kind of key in the +id_and_attributes_pairs+ hash.388 # For example, if you have a view that contains form elements of both existing and new records, you might end up with389 # a hash that looks like this:390 # @params['people'] = { "1" => { "first_name" => "Bob", "last_name" => "Schilling" },391 # "2" => { "first_name" => "Joe", "last_name" => "Tycoon" },392 # "new_person" => { "first_name" => "Mary", "last_name" => "Smith" } }393 # In such a case, you could discriminate against 'updating' the new_person record with the following code:394 # Person.update_collection(@params['people']) { |ar, attrs| ar.id.to_i > 0 }395 #396 # This works because the to_i method converts all non-integer strings to 0.397 def update_collection(id_and_attributes_pairs)398 updated_records = Array.new399 400 transaction do401 records = find(id_and_attributes_pairs.keys)402 id_and_attributes_pairs.each do |id, attrs|403 record = records.select { |r| r.id.to_s == id }.first404 405 # Update each record unless the closure is false406 if (!block_given? || (block_given? && yield(record, attrs)))407 record.update_attributes(attrs)408 updated_records << record409 end410 end411 end412 413 return updated_records414 end415 416 417 386 # Destroys the objects for all the records that matches the +condition+ by instantiating each object and calling 418 387 # the destroy method. Example: trunk/activerecord/test/associations_test.rb
r484 r504 387 387 end 388 388 389 def test_build_many 390 new_clients = @signals37.clients_of_firm.build([{"name" => "Another Client"}, {"name" => "Another Client II"}]) 391 assert_equal 2, new_clients.size 392 393 assert @signals37.save 394 assert_equal 3, @signals37.clients_of_firm(true).size 395 end 396 389 397 def test_invalid_build 390 398 new_client = @signals37.clients_of_firm.build … … 403 411 assert_equal new_client, @signals37.clients_of_firm.last 404 412 assert_equal new_client, @signals37.clients_of_firm(true).last 413 end 414 415 def test_create_many 416 @signals37.clients_of_firm.create([{"name" => "Another Client"}, {"name" => "Another Client II"}]) 417 assert_equal 3, @signals37.clients_of_firm(true).size 405 418 end 406 419 trunk/activerecord/test/base_test.rb
r496 r504 115 115 assert_equal("New Topic", topicReloaded.title) 116 116 end 117 118 def test_create_many 119 topics = Topic.create([ { "title" => "first" }, { "title" => "second" }]) 120 assert_equal 2, topics.size 121 assert_equal "first", topics.first.title 122 end 117 123 118 124 def test_create_columns_not_equal_attributes … … 257 263 258 264 def test_destroy_all 259 assert_equal (2, Topic.find_all.size)265 assert_equal 2, Topic.find_all.size 260 266 261 267 Topic.destroy_all "author_name = 'Mary'" 262 assert_equal(1, Topic.find_all.size) 263 end 264 268 assert_equal 1, Topic.find_all.size 269 end 270 271 def test_destroy_many 272 Client.destroy([2, 3]) 273 assert_equal 0, Client.count 274 end 275 276 def test_delete_many 277 Topic.delete([1, 2]) 278 assert_equal 0, Topic.count 279 end 280 265 281 def test_boolean_attributes 266 282 assert ! Topic.find(1).approved? … … 293 309 end 294 310 295 def test_update_ collection296 ids_and_attributes= { "1" => { "content" => "1 updated" }, "2" => { "content" => "2 updated" } }297 updated = Topic.update _collection(ids_and_attributes)311 def test_update_many 312 topic_data = { "1" => { "content" => "1 updated" }, "2" => { "content" => "2 updated" } } 313 updated = Topic.update(topic_data.keys, topic_data.values) 298 314 299 315 assert_equal 2, updated.size 300 316 assert_equal "1 updated", Topic.find(1).content 301 assert_equal "2 updated", Topic.find(2).content302 303 ids_and_attributes["1"]["content"] = "one updated"304 ids_and_attributes["2"]["content"] = "two updated"305 updated = Topic.update_collection(ids_and_attributes) { |ar, attrs| ar.id == 1 }306 307 assert_equal 1, updated.size308 assert_equal "one updated", Topic.find(1).content309 317 assert_equal "2 updated", Topic.find(2).content 310 318 end