Add a transaction wrapper in add_to_target. This means that #build will now also use a transaction. IMO this is reasonable given that the before_add and after_add callbacks might do anything, and this great consistency allows us to abstract out the duplicate code from #build and #create.

This commit is contained in:
Jon Leighton
2011-02-14 01:40:00 +00:00
parent 5d6d669bfe
commit b9ea751d0e

View File

@@ -56,31 +56,15 @@ module ActiveRecord
end
def build(attributes = {}, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| build(attr, &block) }
else
add_to_target(build_record(attributes)) do |record|
yield(record) if block_given?
set_owner_attributes(record)
end
end
build_or_create(attributes, :build, &block)
end
def create(attributes = {})
def create(attributes = {}, &block)
unless @owner.persisted?
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
end
if attributes.is_a?(Array)
attributes.collect { |attr| create(attr) }
else
transaction do
add_to_target(build_record(attributes)) do |record|
yield(record) if block_given?
insert_record(record)
end
end
end
build_or_create(attributes, :create, &block)
end
def create!(attrs = {}, &block)
@@ -354,17 +338,20 @@ module ActiveRecord
end
def add_to_target(record)
callback(:before_add, record)
yield(record) if block_given?
transaction do
callback(:before_add, record)
yield(record) if block_given?
if @reflection.options[:uniq] && index = @target.index(record)
@target[index] = record
else
@target << record
if @reflection.options[:uniq] && index = @target.index(record)
@target[index] = record
else
@target << record
end
callback(:after_add, record)
set_inverse_instance(record)
end
callback(:after_add, record)
set_inverse_instance(record)
record
end
@@ -425,6 +412,19 @@ module ActiveRecord
end + existing
end
def build_or_create(attributes, method)
records = Array.wrap(attributes).map do |attrs|
record = build_record(attrs)
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