1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
|
module ActiveRecord
module Associations
class Association
def build_record(attributes, options)
reflection.build_association(attributes, options) do |record|
attributes = create_scope.except(*(record.changed - [reflection.foreign_key]))
record.assign_attributes(attributes, without_protection: true)
end
end
private :build_record
end
class CollectionAssociation
def 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?
end
end
end
def create(attributes = {}, options = {}, &block)
create_record(attributes, options, &block)
end
def create!(attributes = {}, options = {}, &block)
create_record(attributes, options, true, &block)
end
def create_record(attributes, options, raise = false, &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_record(attr, options, raise, &block) }
else
transaction do
add_to_target(build_record(attributes, options)) do |record|
yield(record) if block_given?
insert_record(record, true, raise)
end
end
end
end
private :create_record
end
class CollectionProxy
def build(attributes = {}, options = {}, &block)
@association.build(attributes, options, &block)
end
alias_method :new, :build
def create(attributes = {}, options = {}, &block)
@association.create(attributes, options, &block)
end
def create!(attributes = {}, options = {}, &block)
@association.create!(attributes, options, &block)
end
end
class HasManyThroughAssociation
def build_record(attributes, options = {})
ensure_not_nested
record = super(attributes, options)
inverse = source_reflection.inverse_of
if inverse
if inverse.macro == :has_many
record.send(inverse.name) << build_through_record(record)
elsif inverse.macro == :has_one
record.send("#{inverse.name}=", build_through_record(record))
end
end
record
end
private :build_record
def options_for_through_record
[through_scope_attributes, without_protection: true]
end
private :options_for_through_record
end
class SingularAssociation
def create(attributes = {}, options = {}, &block)
create_record(attributes, options, &block)
end
def create!(attributes = {}, options = {}, &block)
create_record(attributes, options, true, &block)
end
def build(attributes = {}, options = {})
record = build_record(attributes, options)
yield(record) if block_given?
set_new_record(record)
record
end
def create_record(attributes, options = {}, raise_error = false)
record = build_record(attributes, options)
yield(record) if block_given?
saved = record.save
set_new_record(record)
raise RecordInvalid.new(record) if !saved && raise_error
record
end
private :create_record
end
end
end
|