diff options
Diffstat (limited to 'activerecord/lib')
4 files changed, 60 insertions, 28 deletions
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index 6cdec8c487..85a4f47b7d 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -94,7 +94,14 @@ module ActiveRecord end def build(attributes = {}, options = {}, &block) - build_or_create(:build, attributes, options, &block) + if attributes.is_a?(Array) + attributes.collect { |attr| build(attr, options, &block) } + else + add_to_target(build_record(attributes, options)) do |record| + yield(record) if block_given? + set_owner_attributes(record) + end + end end def create(attributes = {}, options = {}, &block) @@ -102,7 +109,16 @@ module ActiveRecord raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved" end - build_or_create(:create, attributes, options, &block) + if attributes.is_a?(Array) + attributes.collect { |attr| create(attr, options, &block) } + else + transaction do + add_to_target(build_record(attributes, options)) do |record| + yield(record) if block_given? + insert_record(record) + end + end + end end def create!(attrs = {}, options = {}, &block) @@ -337,20 +353,18 @@ module ActiveRecord end def add_to_target(record) - transaction do - callback(:before_add, record) - yield(record) if block_given? - - if options[:uniq] && index = @target.index(record) - @target[index] = record - else - @target << record - end + callback(:before_add, record) + yield(record) if block_given? - callback(:after_add, record) - set_inverse_instance(record) + if options[:uniq] && index = @target.index(record) + @target[index] = record + else + @target << record end + callback(:after_add, record) + set_inverse_instance(record) + record end @@ -403,26 +417,13 @@ module ActiveRecord end + existing end - def build_or_create(method, attributes, options) - records = Array.wrap(attributes).map do |attrs| - record = build_record(attrs, options) - - add_to_target(record) do - yield(record) if block_given? - insert_record(record) if method == :create - end - end - - attributes.is_a?(Array) ? records : records.first - end - # Do the relevant stuff to insert the given record into the association collection. def insert_record(record, validate = true) raise NotImplementedError end def build_record(attributes, options) - reflection.build_association(scoped.scope_for_create.merge(attributes), options) + reflection.build_association(scoped.scope_for_create.merge(attributes || {}), options) end def delete_or_destroy(records, method) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 67af21c9a0..d07f9365b3 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -1688,6 +1688,8 @@ MSG # user.name # => "Josh" # user.is_admin? # => true def assign_attributes(new_attributes, options = {}) + return unless new_attributes + attributes = new_attributes.stringify_keys role = options[:as] || :default diff --git a/activerecord/lib/active_record/identity_map.rb b/activerecord/lib/active_record/identity_map.rb index cad3865f03..b15b5a8133 100644 --- a/activerecord/lib/active_record/identity_map.rb +++ b/activerecord/lib/active_record/identity_map.rb @@ -12,7 +12,34 @@ module ActiveRecord # In order to enable IdentityMap, set <tt>config.active_record.identity_map = true</tt> # in your <tt>config/application.rb</tt> file. # - # IdentityMap is disabled by default. + # IdentityMap is disabled by default and still in development (i.e. use it with care). + # + # == Associations + # + # Active Record Identity Map does not track associations yet. For example: + # + # comment = @post.comments.first + # comment.post = nil + # @post.comments.include?(comment) #=> true + # + # Ideally, the example above would return false, removing the comment object from the + # post association when the association is nullified. This may cause side effects, as + # in the situation below, if Identity Map is enabled: + # + # Post.has_many :comments, :dependent => :destroy + # + # comment = @post.comments.first + # comment.post = nil + # comment.save + # Post.destroy(@post.id) + # + # Without using Identity Map, the code above will destroy the @post object leaving + # the comment object intact. However, once we enable Identity Map, the post loaded + # by Post.destroy is exactly the same object as the object @post. As the object @post + # still has the comment object in @post.comments, once Identity Map is enabled, the + # comment object will be accidently removed. + # + # This inconsistency is meant to be fixed in future Rails releases. # module IdentityMap diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb index 7e77aefb21..98e21db908 100644 --- a/activerecord/lib/active_record/session_store.rb +++ b/activerecord/lib/active_record/session_store.rb @@ -83,6 +83,8 @@ module ActiveRecord cattr_accessor :data_column_name self.data_column_name = 'data' + attr_accessible :session_id, :data, :marshaled_data + before_save :marshal_data! before_save :raise_on_session_data_overflow! |