diff options
author | José Valim <jose.valim@gmail.com> | 2010-01-07 20:13:07 +0100 |
---|---|---|
committer | José Valim <jose.valim@gmail.com> | 2010-01-07 20:13:07 +0100 |
commit | 423e2acbb7110961a2774ccd191261c031b83d7a (patch) | |
tree | f21f347bc496098226b9b56fd5f459af372d9cdb /activerecord/lib/active_record/nested_attributes.rb | |
parent | 47a5fd4c4ba447c997c0a029adfa80d8b790b25a (diff) | |
parent | 9550916903c931161f04a98091fba712d7fa5c1d (diff) | |
download | rails-423e2acbb7110961a2774ccd191261c031b83d7a.tar.gz rails-423e2acbb7110961a2774ccd191261c031b83d7a.tar.bz2 rails-423e2acbb7110961a2774ccd191261c031b83d7a.zip |
Merge remote branch 'eloy/master'
Diffstat (limited to 'activerecord/lib/active_record/nested_attributes.rb')
-rw-r--r-- | activerecord/lib/active_record/nested_attributes.rb | 53 |
1 files changed, 22 insertions, 31 deletions
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb index ff3a51d5c0..9038888d22 100644 --- a/activerecord/lib/active_record/nested_attributes.rb +++ b/activerecord/lib/active_record/nested_attributes.rb @@ -188,6 +188,8 @@ module ActiveRecord # the parent model is saved. This happens inside the transaction initiated # by the parents save method. See ActiveRecord::AutosaveAssociation. module ClassMethods + REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |_, value| value.blank? } } + # Defines an attributes writer for the specified association(s). If you # are using <tt>attr_protected</tt> or <tt>attr_accessible</tt>, then you # will need to add the attribute writer to the allowed list. @@ -229,23 +231,14 @@ module ActiveRecord options = { :allow_destroy => false, :update_only => false } options.update(attr_names.extract_options!) options.assert_valid_keys(:allow_destroy, :reject_if, :limit, :update_only) + options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank attr_names.each do |association_name| if reflection = reflect_on_association(association_name) - type = case reflection.macro - when :has_one, :belongs_to - :one_to_one - when :has_many, :has_and_belongs_to_many - :collection - end - reflection.options[:autosave] = true add_autosave_association_callbacks(reflection) - self.nested_attributes_options[association_name.to_sym] = options - - if options[:reject_if] == :all_blank - self.nested_attributes_options[association_name.to_sym][:reject_if] = proc { |attributes| attributes.all? {|k,v| v.blank?} } - end + nested_attributes_options[association_name.to_sym] = options + type = (reflection.collection_association? ? :collection : :one_to_one) # def pirate_attributes=(attributes) # assign_nested_attributes_for_one_to_one_association(:pirate, attributes) @@ -271,21 +264,11 @@ module ActiveRecord marked_for_destruction? end - # Deal with deprecated _delete. - # - def _delete #:nodoc: - ActiveSupport::Deprecation.warn "_delete is deprecated in nested attributes. Use _destroy instead." - _destroy - end - private # Attribute hash keys that should not be assigned as normal attributes. # These hash keys are nested attributes implementation details. - # - # TODO Remove _delete from UNASSIGNABLE_KEYS when deprecation warning are - # removed. - UNASSIGNABLE_KEYS = %w( id _destroy _delete ) + UNASSIGNABLE_KEYS = %w( id _destroy ) # Assigns the given attributes to the association. # @@ -298,13 +281,17 @@ module ActiveRecord # update_only is true, and a <tt>:_destroy</tt> key set to a truthy value, # then the existing record will be marked for destruction. def assign_nested_attributes_for_one_to_one_association(association_name, attributes) - options = self.nested_attributes_options[association_name] + options = nested_attributes_options[association_name] attributes = attributes.with_indifferent_access check_existing_record = (options[:update_only] || !attributes['id'].blank?) if check_existing_record && (record = send(association_name)) && (options[:update_only] || record.id.to_s == attributes['id'].to_s) assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy]) + + elsif attributes['id'] + raise_nested_attributes_record_not_found(association_name, attributes['id']) + elsif !reject_new_record?(association_name, attributes) method = "build_#{association_name}" if respond_to?(method) @@ -343,7 +330,7 @@ module ActiveRecord # { :id => '2', :_destroy => true } # ]) def assign_nested_attributes_for_collection_association(association_name, attributes_collection) - options = self.nested_attributes_options[association_name] + options = nested_attributes_options[association_name] unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array) raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})" @@ -366,6 +353,8 @@ module ActiveRecord end elsif existing_record = send(association_name).detect { |record| record.id.to_s == attributes['id'].to_s } assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) + else + raise_nested_attributes_record_not_found(association_name, attributes['id']) end end end @@ -382,8 +371,7 @@ module ActiveRecord # Determines if a hash contains a truthy _destroy key. def has_destroy_flag?(hash) - ConnectionAdapters::Column.value_to_boolean(hash['_destroy']) || - ConnectionAdapters::Column.value_to_boolean(hash['_delete']) # TODO Remove after deprecation. + ConnectionAdapters::Column.value_to_boolean(hash['_destroy']) end # Determines if a new record should be build by checking for @@ -394,14 +382,17 @@ module ActiveRecord end def call_reject_if(association_name, attributes) - callback = self.nested_attributes_options[association_name][:reject_if] - - case callback + case callback = nested_attributes_options[association_name][:reject_if] when Symbol method(callback).arity == 0 ? send(callback) : send(callback, attributes) when Proc - callback.try(:call, attributes) + callback.call(attributes) end end + + def raise_nested_attributes_record_not_found(association_name, record_id) + reflection = self.class.reflect_on_association(association_name) + raise RecordNotFound, "Couldn't find #{reflection.klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}" + end end end |