Started again with Rails 4
[feedcatcher.git] / vendor / rails / activerecord / lib / active_record / autosave_association.rb
diff --git a/vendor/rails/activerecord/lib/active_record/autosave_association.rb b/vendor/rails/activerecord/lib/active_record/autosave_association.rb
deleted file mode 100644 (file)
index 741aa2a..0000000
+++ /dev/null
@@ -1,349 +0,0 @@
-module ActiveRecord
-  # AutosaveAssociation is a module that takes care of automatically saving
-  # your associations when the parent is saved. In addition to saving, it
-  # also destroys any associations that were marked for destruction.
-  # (See mark_for_destruction and marked_for_destruction?)
-  #
-  # Saving of the parent, its associations, and the destruction of marked
-  # associations, all happen inside 1 transaction. This should never leave the
-  # database in an inconsistent state after, for instance, mass assigning
-  # attributes and saving them.
-  #
-  # If validations for any of the associations fail, their error messages will
-  # be applied to the parent.
-  #
-  # Note that it also means that associations marked for destruction won't
-  # be destroyed directly. They will however still be marked for destruction.
-  #
-  # === One-to-one Example
-  #
-  # Consider a Post model with one Author:
-  #
-  #   class Post
-  #     has_one :author, :autosave => true
-  #   end
-  #
-  # Saving changes to the parent and its associated model can now be performed
-  # automatically _and_ atomically:
-  #
-  #   post = Post.find(1)
-  #   post.title # => "The current global position of migrating ducks"
-  #   post.author.name # => "alloy"
-  #
-  #   post.title = "On the migration of ducks"
-  #   post.author.name = "Eloy Duran"
-  #
-  #   post.save
-  #   post.reload
-  #   post.title # => "On the migration of ducks"
-  #   post.author.name # => "Eloy Duran"
-  #
-  # Destroying an associated model, as part of the parent's save action, is as
-  # simple as marking it for destruction:
-  #
-  #   post.author.mark_for_destruction
-  #   post.author.marked_for_destruction? # => true
-  #
-  # Note that the model is _not_ yet removed from the database:
-  #   id = post.author.id
-  #   Author.find_by_id(id).nil? # => false
-  #
-  #   post.save
-  #   post.reload.author # => nil
-  #
-  # Now it _is_ removed from the database:
-  #   Author.find_by_id(id).nil? # => true
-  #
-  # === One-to-many Example
-  #
-  # Consider a Post model with many Comments:
-  #
-  #   class Post
-  #     has_many :comments, :autosave => true
-  #   end
-  #
-  # Saving changes to the parent and its associated model can now be performed
-  # automatically _and_ atomically:
-  #
-  #   post = Post.find(1)
-  #   post.title # => "The current global position of migrating ducks"
-  #   post.comments.first.body # => "Wow, awesome info thanks!"
-  #   post.comments.last.body # => "Actually, your article should be named differently."
-  #
-  #   post.title = "On the migration of ducks"
-  #   post.comments.last.body = "Actually, your article should be named differently. [UPDATED]: You are right, thanks."
-  #
-  #   post.save
-  #   post.reload
-  #   post.title # => "On the migration of ducks"
-  #   post.comments.last.body # => "Actually, your article should be named differently. [UPDATED]: You are right, thanks."
-  #
-  # Destroying one of the associated models members, as part of the parent's
-  # save action, is as simple as marking it for destruction:
-  #
-  #   post.comments.last.mark_for_destruction
-  #   post.comments.last.marked_for_destruction? # => true
-  #   post.comments.length # => 2
-  #
-  # Note that the model is _not_ yet removed from the database:
-  #   id = post.comments.last.id
-  #   Comment.find_by_id(id).nil? # => false
-  #
-  #   post.save
-  #   post.reload.comments.length # => 1
-  #
-  # Now it _is_ removed from the database:
-  #   Comment.find_by_id(id).nil? # => true
-  #
-  # === Validation
-  #
-  # Validation is performed on the parent as usual, but also on all autosave
-  # enabled associations. If any of the associations fail validation, its
-  # error messages will be applied on the parents errors object and validation
-  # of the parent will fail.
-  #
-  # Consider a Post model with Author which validates the presence of its name
-  # attribute:
-  #
-  #   class Post
-  #     has_one :author, :autosave => true
-  #   end
-  #
-  #   class Author
-  #     validates_presence_of :name
-  #   end
-  #
-  #   post = Post.find(1)
-  #   post.author.name = ''
-  #   post.save # => false
-  #   post.errors # => #<ActiveRecord::Errors:0x174498c @errors={"author_name"=>["can't be blank"]}, @base=#<Post ...>>
-  #
-  # No validations will be performed on the associated models when validations
-  # are skipped for the parent:
-  #
-  #   post = Post.find(1)
-  #   post.author.name = ''
-  #   post.save(false) # => true
-  module AutosaveAssociation
-    ASSOCIATION_TYPES = %w{ has_one belongs_to has_many has_and_belongs_to_many }
-
-    def self.included(base)
-      base.class_eval do
-        base.extend(ClassMethods)
-        alias_method_chain :reload, :autosave_associations
-
-        ASSOCIATION_TYPES.each do |type|
-          base.send("valid_keys_for_#{type}_association") << :autosave
-        end
-      end
-    end
-
-    module ClassMethods
-      private
-
-      # def belongs_to(name, options = {})
-      #   super
-      #   add_autosave_association_callbacks(reflect_on_association(name))
-      # end
-      ASSOCIATION_TYPES.each do |type|
-        module_eval %{
-          def #{type}(name, options = {})
-            super
-            add_autosave_association_callbacks(reflect_on_association(name))
-          end
-        }
-      end
-
-      # Adds a validate and save callback for the association as specified by
-      # the +reflection+.
-      def add_autosave_association_callbacks(reflection)
-        save_method = "autosave_associated_records_for_#{reflection.name}"
-        validation_method = "validate_associated_records_for_#{reflection.name}"
-        validate validation_method
-
-        case reflection.macro
-        when :has_many, :has_and_belongs_to_many
-          before_save :before_save_collection_association
-
-          define_method(save_method) { save_collection_association(reflection) }
-          # Doesn't use after_save as that would save associations added in after_create/after_update twice
-          after_create save_method
-          after_update save_method
-
-          define_method(validation_method) { validate_collection_association(reflection) }
-        else
-          case reflection.macro
-          when :has_one
-            define_method(save_method) { save_has_one_association(reflection) }
-            after_save save_method
-          when :belongs_to
-            define_method(save_method) { save_belongs_to_association(reflection) }
-            before_save save_method
-          end
-          define_method(validation_method) { validate_single_association(reflection) }
-        end
-      end
-    end
-
-    # Reloads the attributes of the object as usual and removes a mark for destruction.
-    def reload_with_autosave_associations(options = nil)
-      @marked_for_destruction = false
-      reload_without_autosave_associations(options)
-    end
-
-    # Marks this record to be destroyed as part of the parents save transaction.
-    # This does _not_ actually destroy the record yet, rather it will be destroyed when <tt>parent.save</tt> is called.
-    #
-    # Only useful if the <tt>:autosave</tt> option on the parent is enabled for this associated model.
-    def mark_for_destruction
-      @marked_for_destruction = true
-    end
-
-    # Returns whether or not this record will be destroyed as part of the parents save transaction.
-    #
-    # Only useful if the <tt>:autosave</tt> option on the parent is enabled for this associated model.
-    def marked_for_destruction?
-      @marked_for_destruction
-    end
-
-    private
-
-    # Returns the record for an association collection that should be validated
-    # or saved. If +autosave+ is +false+ only new records will be returned,
-    # unless the parent is/was a new record itself.
-    def associated_records_to_validate_or_save(association, new_record, autosave)
-      if new_record
-        association
-      elsif association.loaded?
-        autosave ? association : association.select { |record| record.new_record? }
-      else
-        autosave ? association.target : association.target.select { |record| record.new_record? }
-      end
-    end
-
-    # Validate the association if <tt>:validate</tt> or <tt>:autosave</tt> is
-    # turned on for the association specified by +reflection+.
-    def validate_single_association(reflection)
-      if reflection.options[:validate] == true || reflection.options[:autosave] == true
-        if (association = association_instance_get(reflection.name)) && !association.target.nil?
-          association_valid?(reflection, association)
-        end
-      end
-    end
-
-    # Validate the associated records if <tt>:validate</tt> or
-    # <tt>:autosave</tt> is turned on for the association specified by
-    # +reflection+.
-    def validate_collection_association(reflection)
-      if reflection.options[:validate] != false && association = association_instance_get(reflection.name)
-        if records = associated_records_to_validate_or_save(association, new_record?, reflection.options[:autosave])
-          records.each { |record| association_valid?(reflection, record) }
-        end
-      end
-    end
-
-    # Returns whether or not the association is valid and applies any errors to
-    # the parent, <tt>self</tt>, if it wasn't. Skips any <tt>:autosave</tt>
-    # enabled records if they're marked_for_destruction?.
-    def association_valid?(reflection, association)
-      unless valid = association.valid?
-        if reflection.options[:autosave]
-          unless association.marked_for_destruction?
-            association.errors.each do |attribute, message|
-              attribute = "#{reflection.name}_#{attribute}"
-              errors.add(attribute, message) unless errors.on(attribute)
-            end
-          end
-        else
-          errors.add(reflection.name)
-        end
-      end
-      valid
-    end
-
-    # Is used as a before_save callback to check while saving a collection
-    # association whether or not the parent was a new record before saving.
-    def before_save_collection_association
-      @new_record_before_save = new_record?
-      true
-    end
-
-    # Saves any new associated records, or all loaded autosave associations if
-    # <tt>:autosave</tt> is enabled on the association.
-    #
-    # In addition, it destroys all children that were marked for destruction
-    # with mark_for_destruction.
-    #
-    # This all happens inside a transaction, _if_ the Transactions module is included into
-    # ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
-    def save_collection_association(reflection)
-      if association = association_instance_get(reflection.name)
-        autosave = reflection.options[:autosave]
-
-        if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
-          records.each do |record|
-            if autosave && record.marked_for_destruction?
-              association.destroy(record)
-            elsif @new_record_before_save || record.new_record?
-              if autosave
-                association.send(:insert_record, record, false, false)
-              else
-                association.send(:insert_record, record)
-              end
-            elsif autosave
-              record.save(false)
-            end
-          end
-        end
-
-        # reconstruct the SQL queries now that we know the owner's id
-        association.send(:construct_sql) if association.respond_to?(:construct_sql)
-      end
-    end
-
-    # Saves the associated record if it's new or <tt>:autosave</tt> is enabled
-    # on the association.
-    #
-    # In addition, it will destroy the association if it was marked for
-    # destruction with mark_for_destruction.
-    #
-    # This all happens inside a transaction, _if_ the Transactions module is included into
-    # ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
-    def save_has_one_association(reflection)
-      if (association = association_instance_get(reflection.name)) && !association.target.nil?
-        if reflection.options[:autosave] && association.marked_for_destruction?
-          association.destroy
-        elsif new_record? || association.new_record? || association[reflection.primary_key_name] != id || reflection.options[:autosave]
-          association[reflection.primary_key_name] = id
-          association.save(false)
-        end
-      end
-    end
-
-    # Saves the associated record if it's new or <tt>:autosave</tt> is enabled
-    # on the association.
-    #
-    # In addition, it will destroy the association if it was marked for
-    # destruction with mark_for_destruction.
-    #
-    # This all happens inside a transaction, _if_ the Transactions module is included into
-    # ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
-    def save_belongs_to_association(reflection)
-      if association = association_instance_get(reflection.name)
-        if reflection.options[:autosave] && association.marked_for_destruction?
-          association.destroy
-        else
-          association.save(false) if association.new_record? || reflection.options[:autosave]
-
-          if association.updated?
-            self[reflection.primary_key_name] = association.id
-            # TODO: Removing this code doesn't seem to matter…
-            if reflection.options[:polymorphic]
-              self[reflection.options[:foreign_type]] = association.class.base_class.name.to_s
-            end
-          end
-        end
-      end
-    end
-  end
-end
\ No newline at end of file