diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2005-06-16 05:35:10 +0000 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2005-06-16 05:35:10 +0000 |
commit | bfe6a759c25ad02b4bfcb2dd16999d8ba72e2df8 (patch) | |
tree | 0d3274d426dc294ec0deb6109d547162391738c1 /activerecord/lib | |
parent | 7b47f150fd73dc84652498a960fc17b601e77a0a (diff) | |
download | rails-bfe6a759c25ad02b4bfcb2dd16999d8ba72e2df8.tar.gz rails-bfe6a759c25ad02b4bfcb2dd16999d8ba72e2df8.tar.bz2 rails-bfe6a759c25ad02b4bfcb2dd16999d8ba72e2df8.zip |
Added actual database-changing behavior to collection assigment for has_many and has_and_belongs_to_many #1425 [Sebastian Kanthak]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1428 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'activerecord/lib')
-rwxr-xr-x | activerecord/lib/active_record/associations.rb | 18 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/association_collection.rb | 16 |
2 files changed, 30 insertions, 4 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 93960f87e4..65549aca0c 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -200,6 +200,8 @@ module ActiveRecord # * <tt>collection<<(object, ...)</tt> - adds one or more objects to the collection by setting their foreign keys to the collection's primary key. # * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by setting their foreign keys to NULL. # This will also destroy the objects if they're declared as belongs_to and dependent on this model. + # * <tt>collection=objects</tt> - replaces the collections content by deleting and adding objects as appropriate. + # * <tt>collection_singular_ids=ids</tt> - replace the collection by the objects identified by the primary keys in +ids+ # * <tt>collection.clear</tt> - removes every object from the collection. This does not destroy the objects. # * <tt>collection.empty?</tt> - returns true if there are no associated objects. # * <tt>collection.size</tt> - returns the number of associated objects. @@ -215,6 +217,8 @@ module ActiveRecord # * <tt>Firm#clients</tt> (similar to <tt>Clients.find :all, :conditions => "firm_id = #{id}"</tt>) # * <tt>Firm#clients<<</tt> # * <tt>Firm#clients.delete</tt> + # * <tt>Firm#clients=</tt> + # * <tt>Firm#client_ids=</tt> # * <tt>Firm#clients.clear</tt> # * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>) # * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>) @@ -463,6 +467,8 @@ module ActiveRecord # (collection.concat_with_attributes is an alias to this method). # * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by removing their associations from the join table. # This does not destroy the objects. + # * <tt>collection=objects</tt> - replaces the collections content by deleting and adding objects as appropriate. + # * <tt>collection_singular_ids=ids</tt> - replace the collection by the objects identified by the primary keys in +ids+ # * <tt>collection.clear</tt> - removes every object from the collection. This does not destroy the objects. # * <tt>collection.empty?</tt> - returns true if there are no associated objects. # * <tt>collection.size</tt> - returns the number of associated objects. @@ -474,6 +480,8 @@ module ActiveRecord # * <tt>Developer#projects<<</tt> # * <tt>Developer#projects.push_with_attributes</tt> # * <tt>Developer#projects.delete</tt> + # * <tt>Developer#projects=</tt> + # * <tt>Developer#project_ids=</tt> # * <tt>Developer#projects.clear</tt> # * <tt>Developer#projects.empty?</tt> # * <tt>Developer#projects.size</tt> @@ -634,6 +642,10 @@ module ActiveRecord association.replace(new_value) association end + + define_method("#{Inflector.singularize(association_name)}_ids=") do |new_value| + send("#{association_name}=", association_class_name.constantize.find(new_value)) + end end def require_association_class(class_name) @@ -687,7 +699,11 @@ module ActiveRecord instance_variable_set("@#{association_name}", association) end - association.send(constructor, attributees, replace_existing) + if association_proxy_class == HasOneAssociation + association.send(constructor, attributees, replace_existing) + else + association.send(constructor, attributees) + end end end diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb index 1eac8a2a0b..4495d92151 100644 --- a/activerecord/lib/active_record/associations/association_collection.rb +++ b/activerecord/lib/active_record/associations/association_collection.rb @@ -1,3 +1,5 @@ +require 'set' + module ActiveRecord module Associations class AssociationCollection < AssociationProxy #:nodoc: @@ -83,11 +85,19 @@ module ActiveRecord collection.inject([]) { |uniq_records, record| uniq_records << record unless uniq_records.include?(record); uniq_records } end + # Replace this collection with +other_array+ + # This will perform a diff and delete/add only records that have changed. def replace(other_array) - other_array.each{ |val| raise_on_type_mismatch(val) } + other_array.each { |val| raise_on_type_mismatch(val) } + + load_target + other = other_array.size < 100 ? other_array : other_array.to_set + current = @target.size < 100 ? @target : @target.to_set - @target = other_array - @loaded = true + @owner.transaction do + delete(@target.select { |v| !other.include?(v) }) + concat(other_array.select { |v| !current.include?(v) }) + end end private |