active_data 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.codeclimate.yml +13 -0
- data/.rubocop.yml +56 -0
- data/.rubocop_todo.yml +53 -0
- data/.rvmrc +1 -1
- data/.travis.yml +15 -2
- data/Appraisals +1 -1
- data/CHANGELOG.md +31 -0
- data/Guardfile +8 -8
- data/README.md +256 -0
- data/Rakefile +2 -4
- data/active_data.gemspec +8 -7
- data/gemfiles/rails.4.0.gemfile +1 -1
- data/gemfiles/rails.4.1.gemfile +1 -1
- data/gemfiles/rails.4.2.gemfile +1 -1
- data/gemfiles/rails.5.0.gemfile +1 -1
- data/gemfiles/rails.5.1.gemfile +14 -0
- data/lib/active_data/active_record/associations.rb +18 -13
- data/lib/active_data/active_record/nested_attributes.rb +8 -14
- data/lib/active_data/base.rb +13 -0
- data/lib/active_data/config.rb +4 -4
- data/lib/active_data/errors.rb +29 -13
- data/lib/active_data/extensions.rb +22 -21
- data/lib/active_data/model/associations/base.rb +22 -6
- data/lib/active_data/model/associations/embeds_any.rb +17 -0
- data/lib/active_data/model/associations/embeds_many.rb +29 -19
- data/lib/active_data/model/associations/embeds_one.rb +30 -26
- data/lib/active_data/model/associations/nested_attributes.rb +82 -50
- data/lib/active_data/model/associations/persistence_adapters/active_record/referenced_proxy.rb +31 -0
- data/lib/active_data/model/associations/persistence_adapters/active_record.rb +66 -0
- data/lib/active_data/model/associations/persistence_adapters/base.rb +53 -0
- data/lib/active_data/model/associations/references_any.rb +41 -0
- data/lib/active_data/model/associations/references_many.rb +51 -37
- data/lib/active_data/model/associations/references_one.rb +43 -41
- data/lib/active_data/model/associations/reflections/base.rb +19 -29
- data/lib/active_data/model/associations/reflections/embeds_any.rb +43 -0
- data/lib/active_data/model/associations/reflections/embeds_many.rb +3 -13
- data/lib/active_data/model/associations/reflections/embeds_one.rb +5 -37
- data/lib/active_data/model/associations/reflections/references_any.rb +62 -0
- data/lib/active_data/model/associations/reflections/references_many.rb +7 -7
- data/lib/active_data/model/associations/reflections/references_one.rb +9 -7
- data/lib/active_data/model/associations/reflections/singular.rb +35 -0
- data/lib/active_data/model/associations/validations.rb +2 -27
- data/lib/active_data/model/associations.rb +12 -10
- data/lib/active_data/model/attributes/attribute.rb +10 -10
- data/lib/active_data/model/attributes/base.rb +8 -7
- data/lib/active_data/model/attributes/localized.rb +4 -4
- data/lib/active_data/model/attributes/reference_many.rb +6 -8
- data/lib/active_data/model/attributes/reference_one.rb +17 -9
- data/lib/active_data/model/attributes/reflections/attribute.rb +2 -2
- data/lib/active_data/model/attributes/reflections/base.rb +8 -11
- data/lib/active_data/model/attributes/reflections/localized.rb +2 -2
- data/lib/active_data/model/attributes/reflections/reference_one.rb +11 -22
- data/lib/active_data/model/attributes/reflections/represents.rb +5 -6
- data/lib/active_data/model/attributes/represents.rb +6 -5
- data/lib/active_data/model/attributes.rb +33 -87
- data/lib/active_data/model/callbacks.rb +6 -7
- data/lib/active_data/model/conventions.rb +2 -0
- data/lib/active_data/model/dirty.rb +4 -4
- data/lib/active_data/model/lifecycle.rb +18 -20
- data/lib/active_data/model/localization.rb +5 -2
- data/lib/active_data/model/persistence.rb +2 -2
- data/lib/active_data/model/primary.rb +19 -14
- data/lib/active_data/model/representation.rb +81 -0
- data/lib/active_data/model/scopes.rb +22 -12
- data/lib/active_data/model/validations/associated.rb +3 -2
- data/lib/active_data/model/validations/nested.rb +6 -1
- data/lib/active_data/model/validations.rb +3 -3
- data/lib/active_data/model.rb +2 -1
- data/lib/active_data/undefined_class.rb +9 -0
- data/lib/active_data/version.rb +1 -1
- data/lib/active_data.rb +40 -17
- data/spec/lib/active_data/active_record/associations_spec.rb +107 -45
- data/spec/lib/active_data/active_record/nested_attributes_spec.rb +1 -2
- data/spec/lib/active_data/config_spec.rb +37 -15
- data/spec/lib/active_data/model/associations/embeds_many_spec.rb +475 -172
- data/spec/lib/active_data/model/associations/embeds_one_spec.rb +353 -96
- data/spec/lib/active_data/model/associations/nested_attributes_spec.rb +108 -12
- data/spec/lib/active_data/model/associations/persistence_adapters/active_record_spec.rb +58 -0
- data/spec/lib/active_data/model/associations/references_many_spec.rb +440 -64
- data/spec/lib/active_data/model/associations/references_one_spec.rb +347 -36
- data/spec/lib/active_data/model/associations/reflections/embeds_many_spec.rb +8 -7
- data/spec/lib/active_data/model/associations/reflections/embeds_one_spec.rb +7 -6
- data/spec/lib/active_data/model/associations/reflections/references_many_spec.rb +81 -33
- data/spec/lib/active_data/model/associations/reflections/references_one_spec.rb +116 -37
- data/spec/lib/active_data/model/associations/validations_spec.rb +27 -43
- data/spec/lib/active_data/model/associations_spec.rb +34 -25
- data/spec/lib/active_data/model/attributes/attribute_spec.rb +26 -23
- data/spec/lib/active_data/model/attributes/base_spec.rb +5 -6
- data/spec/lib/active_data/model/attributes/collection_spec.rb +7 -8
- data/spec/lib/active_data/model/attributes/dictionary_spec.rb +40 -33
- data/spec/lib/active_data/model/attributes/localized_spec.rb +27 -28
- data/spec/lib/active_data/model/attributes/reflections/attribute_spec.rb +6 -6
- data/spec/lib/active_data/model/attributes/represents_spec.rb +10 -78
- data/spec/lib/active_data/model/attributes_spec.rb +150 -45
- data/spec/lib/active_data/model/callbacks_spec.rb +69 -70
- data/spec/lib/active_data/model/conventions_spec.rb +0 -1
- data/spec/lib/active_data/model/dirty_spec.rb +22 -13
- data/spec/lib/active_data/model/lifecycle_spec.rb +49 -23
- data/spec/lib/active_data/model/persistence_spec.rb +5 -6
- data/spec/lib/active_data/model/representation_spec.rb +126 -0
- data/spec/lib/active_data/model/scopes_spec.rb +1 -3
- data/spec/lib/active_data/model/typecasting_spec.rb +6 -5
- data/spec/lib/active_data/model/validations/associated_spec.rb +26 -18
- data/spec/lib/active_data/model/validations/nested_spec.rb +89 -18
- data/spec/lib/active_data/model_spec.rb +1 -2
- data/spec/lib/active_data_spec.rb +0 -1
- data/spec/shared/nested_attribute_examples.rb +332 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/model_helpers.rb +2 -2
- data/spec/support/muffle_helper.rb +7 -0
- metadata +52 -18
- data/lib/active_data/model/associations/collection/referenced.rb +0 -26
- data/lib/active_data/model/associations/reflections/reference_reflection.rb +0 -45
- data/spec/lib/active_data/model/nested_attributes.rb +0 -202
|
@@ -3,21 +3,15 @@ module ActiveData
|
|
|
3
3
|
module NestedAttributes
|
|
4
4
|
extend ActiveSupport::Concern
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
module ClassMethods
|
|
11
|
-
def accepts_nested_attributes_for_with_active_data *attr_names
|
|
12
|
-
options = attr_names.extract_options!
|
|
13
|
-
active_data_associations, active_record_association = attr_names.partition do |association_name|
|
|
14
|
-
reflect_on_association(association_name).is_a?(ActiveData::Model::Associations::Reflections::Base)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
ActiveData::Model::Associations::NestedAttributes::NestedAttributesMethods
|
|
18
|
-
.accepts_nested_attributes_for self, *active_data_associations, options.dup
|
|
19
|
-
accepts_nested_attributes_for_without_active_data *active_record_association, options.dup
|
|
6
|
+
def accepts_nested_attributes_for(*attr_names)
|
|
7
|
+
options = attr_names.extract_options!
|
|
8
|
+
active_data_associations, active_record_association = attr_names.partition do |association_name|
|
|
9
|
+
reflect_on_association(association_name).is_a?(ActiveData::Model::Associations::Reflections::Base)
|
|
20
10
|
end
|
|
11
|
+
|
|
12
|
+
ActiveData::Model::Associations::NestedAttributes::NestedAttributesMethods
|
|
13
|
+
.accepts_nested_attributes_for(self, *active_data_associations, options.dup)
|
|
14
|
+
super(*active_record_association, options.dup)
|
|
21
15
|
end
|
|
22
16
|
end
|
|
23
17
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'active_data/model'
|
|
2
|
+
require 'active_data/model/primary'
|
|
3
|
+
require 'active_data/model/lifecycle'
|
|
4
|
+
require 'active_data/model/associations'
|
|
5
|
+
|
|
6
|
+
module ActiveData
|
|
7
|
+
class Base
|
|
8
|
+
include ActiveData::Model
|
|
9
|
+
include ActiveData::Model::Primary
|
|
10
|
+
include ActiveData::Model::Lifecycle
|
|
11
|
+
include ActiveData::Model::Associations
|
|
12
|
+
end
|
|
13
|
+
end
|
data/lib/active_data/config.rb
CHANGED
|
@@ -18,22 +18,22 @@ module ActiveData
|
|
|
18
18
|
@_typecasters = {}
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def normalizer
|
|
21
|
+
def normalizer(name, &block)
|
|
22
22
|
if block
|
|
23
23
|
_normalizers[name.to_sym] = block
|
|
24
24
|
else
|
|
25
|
-
_normalizers[name.to_sym] or raise NormalizerMissing
|
|
25
|
+
_normalizers[name.to_sym] or raise NormalizerMissing, name
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def typecaster
|
|
29
|
+
def typecaster(*classes, &block)
|
|
30
30
|
classes = classes.flatten
|
|
31
31
|
if block
|
|
32
32
|
_typecasters[classes.first.to_s.camelize] = block
|
|
33
33
|
else
|
|
34
34
|
_typecasters[classes.detect do |klass|
|
|
35
35
|
_typecasters[klass.to_s.camelize]
|
|
36
|
-
end.to_s.camelize] or raise TypecasterMissing
|
|
36
|
+
end.to_s.camelize] or raise TypecasterMissing, classes
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
end
|
data/lib/active_data/errors.rb
CHANGED
|
@@ -11,7 +11,7 @@ module ActiveData
|
|
|
11
11
|
|
|
12
12
|
def initialize(model)
|
|
13
13
|
@model = model
|
|
14
|
-
errors = @model.errors.full_messages.join(
|
|
14
|
+
errors = @model.errors.full_messages.join(', ')
|
|
15
15
|
super(I18n.t(:"#{@model.class.i18n_scope}.errors.messages.model_invalid", errors: errors, default: :'errors.messages.model_invalid'))
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -32,13 +32,13 @@ module ActiveData
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
class AssociationTypeMismatch < ActiveDataError
|
|
35
|
-
def initialize
|
|
35
|
+
def initialize(expected, got)
|
|
36
36
|
super "Expected `#{expected}` (##{expected.object_id}), but got `#{got}` (##{got.object_id})"
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
class ObjectNotFound < ActiveDataError
|
|
41
|
-
def initialize
|
|
41
|
+
def initialize(object, association_name, record_id)
|
|
42
42
|
message = "Couldn't find #{object.class.reflect_on_association(association_name).klass.name}" \
|
|
43
43
|
"with #{object.respond_to?(:_primary_name) ? object._primary_name : 'id'} = #{record_id} for #{object.inspect}"
|
|
44
44
|
super message
|
|
@@ -46,14 +46,14 @@ module ActiveData
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
class TooManyObjects < ActiveDataError
|
|
49
|
-
def initialize
|
|
49
|
+
def initialize(limit, actual_size)
|
|
50
50
|
super "Maximum #{limit} objects are allowed. Got #{actual_size} objects instead."
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
class UndefinedPrimaryAttribute < ActiveDataError
|
|
55
|
-
def initialize
|
|
56
|
-
super <<-
|
|
55
|
+
def initialize(klass, association_name)
|
|
56
|
+
super <<-MESSAGE
|
|
57
57
|
Undefined primary attribute for `#{association_name}` in #{klass}.
|
|
58
58
|
It is required for embeds_many nested attributes proper operation.
|
|
59
59
|
You can define this association as:
|
|
@@ -61,33 +61,49 @@ You can define this association as:
|
|
|
61
61
|
embeds_many :#{association_name} do
|
|
62
62
|
primary :attribute_name
|
|
63
63
|
end
|
|
64
|
-
|
|
64
|
+
MESSAGE
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
class NormalizerMissing < NoMethodError
|
|
69
|
-
def initialize
|
|
70
|
-
super <<-
|
|
69
|
+
def initialize(name)
|
|
70
|
+
super <<-MESSAGE
|
|
71
71
|
Could not find normalizer `:#{name}`
|
|
72
72
|
You can define it with:
|
|
73
73
|
|
|
74
74
|
ActiveData.normalizer(:#{name}) do |value, options|
|
|
75
75
|
# do some staff with value and options
|
|
76
76
|
end
|
|
77
|
-
|
|
77
|
+
MESSAGE
|
|
78
78
|
end
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
class TypecasterMissing < NoMethodError
|
|
82
|
-
def initialize
|
|
83
|
-
|
|
82
|
+
def initialize(*classes)
|
|
83
|
+
classes = classes.flatten
|
|
84
|
+
super <<-MESSAGE
|
|
84
85
|
Could not find typecaster for #{classes}
|
|
85
86
|
You can define it with:
|
|
86
87
|
|
|
87
88
|
ActiveData.typecaster('#{classes.first}') do |value|
|
|
88
89
|
# do some staff with value and options
|
|
89
90
|
end
|
|
90
|
-
|
|
91
|
+
MESSAGE
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
class PersistenceAdapterMissing < NoMethodError
|
|
96
|
+
def initialize(data_source)
|
|
97
|
+
super <<-MESSAGE
|
|
98
|
+
Could not find persistence adapter for #{data_source}
|
|
99
|
+
You can define it with:
|
|
100
|
+
|
|
101
|
+
class #{data_source}
|
|
102
|
+
def self.active_data_persistence_adapter
|
|
103
|
+
#{data_source}ActiveDataPersistenceAdapter
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
MESSAGE
|
|
91
107
|
end
|
|
92
108
|
end
|
|
93
109
|
end
|
|
@@ -1,33 +1,34 @@
|
|
|
1
|
-
unless defined?(Boolean)
|
|
2
|
-
class Boolean; end
|
|
3
|
-
end
|
|
1
|
+
class Boolean; end unless defined?(Boolean)
|
|
4
2
|
|
|
5
3
|
begin
|
|
6
4
|
require 'uuidtools'
|
|
7
5
|
rescue LoadError
|
|
6
|
+
nil
|
|
8
7
|
else
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
module ActiveData
|
|
9
|
+
class UUID < UUIDTools::UUID
|
|
10
|
+
def as_json(*_)
|
|
11
|
+
to_s
|
|
12
|
+
end
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
def to_param
|
|
15
|
+
to_s
|
|
16
|
+
end
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
def self.parse_string(value)
|
|
19
|
+
return nil if value.length.zero?
|
|
20
|
+
if value.length == 36
|
|
21
|
+
parse value
|
|
22
|
+
elsif value.length == 32
|
|
23
|
+
parse_hexdigest value
|
|
24
|
+
else
|
|
25
|
+
parse_raw value
|
|
26
|
+
end
|
|
26
27
|
end
|
|
27
|
-
end
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
def inspect
|
|
30
|
+
"#<ActiveData::UUID:#{self}>"
|
|
31
|
+
end
|
|
31
32
|
end
|
|
32
33
|
end
|
|
33
34
|
end
|
|
@@ -5,8 +5,9 @@ module ActiveData
|
|
|
5
5
|
attr_accessor :owner, :reflection
|
|
6
6
|
delegate :macro, :collection?, to: :reflection
|
|
7
7
|
|
|
8
|
-
def initialize
|
|
9
|
-
@owner
|
|
8
|
+
def initialize(owner, reflection)
|
|
9
|
+
@owner = owner
|
|
10
|
+
@reflection = reflection
|
|
10
11
|
@evar_loaded = owner.persisted?
|
|
11
12
|
reset
|
|
12
13
|
end
|
|
@@ -43,9 +44,24 @@ module ActiveData
|
|
|
43
44
|
apply_changes or raise ActiveData::AssociationChangesNotApplied
|
|
44
45
|
end
|
|
45
46
|
|
|
46
|
-
def
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
def callback(name, object)
|
|
48
|
+
evaluator = reflection.options[name]
|
|
49
|
+
return true unless evaluator
|
|
50
|
+
|
|
51
|
+
if evaluator.is_a?(Proc)
|
|
52
|
+
if evaluator.arity == 1
|
|
53
|
+
owner.instance_exec(object, &evaluator)
|
|
54
|
+
else
|
|
55
|
+
evaluator.call(owner, object)
|
|
56
|
+
end
|
|
57
|
+
else
|
|
58
|
+
owner.send(evaluator, object)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def transaction
|
|
63
|
+
data = read_source.deep_dup
|
|
64
|
+
yield
|
|
49
65
|
rescue StandardError => e
|
|
50
66
|
write_source data
|
|
51
67
|
reload
|
|
@@ -62,7 +78,7 @@ module ActiveData
|
|
|
62
78
|
reflection.read_source owner
|
|
63
79
|
end
|
|
64
80
|
|
|
65
|
-
def write_source
|
|
81
|
+
def write_source(value)
|
|
66
82
|
reflection.write_source owner, value
|
|
67
83
|
end
|
|
68
84
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module ActiveData
|
|
2
|
+
module Model
|
|
3
|
+
module Associations
|
|
4
|
+
class EmbedsAny < Base
|
|
5
|
+
private
|
|
6
|
+
|
|
7
|
+
def build_object(attributes)
|
|
8
|
+
reflection.klass.new(attributes)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def embed_object(object)
|
|
12
|
+
object.instance_variable_set(:@embedder, owner)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
module ActiveData
|
|
2
2
|
module Model
|
|
3
3
|
module Associations
|
|
4
|
-
class EmbedsMany <
|
|
5
|
-
def build
|
|
6
|
-
push_object(
|
|
4
|
+
class EmbedsMany < EmbedsAny
|
|
5
|
+
def build(attributes = {})
|
|
6
|
+
push_object(build_object(attributes))
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def create
|
|
9
|
+
def create(attributes = {})
|
|
10
10
|
build(attributes).tap(&:save)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def create!
|
|
13
|
+
def create!(attributes = {})
|
|
14
14
|
build(attributes).tap(&:save!)
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -27,7 +27,7 @@ module ActiveData
|
|
|
27
27
|
result
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def target=
|
|
30
|
+
def target=(objects)
|
|
31
31
|
objects.each { |object| setup_performers! object }
|
|
32
32
|
loaded!
|
|
33
33
|
@target = objects
|
|
@@ -47,7 +47,7 @@ module ActiveData
|
|
|
47
47
|
else
|
|
48
48
|
default.map do |attributes|
|
|
49
49
|
reflection.klass.with_sanitize(false) do
|
|
50
|
-
|
|
50
|
+
build_object(attributes)
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
end
|
|
@@ -63,16 +63,20 @@ module ActiveData
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def clear
|
|
66
|
-
|
|
66
|
+
begin
|
|
67
|
+
transaction { target.all?(&:destroy!) }
|
|
68
|
+
rescue ActiveData::ObjectNotDestroyed
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
67
71
|
reload.empty?
|
|
68
72
|
end
|
|
69
73
|
|
|
70
|
-
def reader
|
|
74
|
+
def reader(force_reload = false)
|
|
71
75
|
reload if force_reload
|
|
72
76
|
@proxy ||= Collection::Embedded.new self
|
|
73
77
|
end
|
|
74
78
|
|
|
75
|
-
def replace
|
|
79
|
+
def replace(objects)
|
|
76
80
|
transaction do
|
|
77
81
|
clear
|
|
78
82
|
append(objects) or raise ActiveData::AssociationChangesNotApplied
|
|
@@ -80,7 +84,7 @@ module ActiveData
|
|
|
80
84
|
end
|
|
81
85
|
alias_method :writer, :replace
|
|
82
86
|
|
|
83
|
-
def concat
|
|
87
|
+
def concat(*objects)
|
|
84
88
|
append objects.flatten
|
|
85
89
|
end
|
|
86
90
|
|
|
@@ -90,7 +94,7 @@ module ActiveData
|
|
|
90
94
|
super || []
|
|
91
95
|
end
|
|
92
96
|
|
|
93
|
-
def append
|
|
97
|
+
def append(objects)
|
|
94
98
|
objects.each do |object|
|
|
95
99
|
raise AssociationTypeMismatch.new(reflection.klass, object.class) unless object && object.is_a?(reflection.klass)
|
|
96
100
|
push_object object
|
|
@@ -99,19 +103,23 @@ module ActiveData
|
|
|
99
103
|
result && target
|
|
100
104
|
end
|
|
101
105
|
|
|
102
|
-
def push_object
|
|
106
|
+
def push_object(object)
|
|
103
107
|
setup_performers! object
|
|
104
108
|
target[target.size] = object
|
|
109
|
+
object
|
|
105
110
|
end
|
|
106
111
|
|
|
107
|
-
def setup_performers!
|
|
112
|
+
def setup_performers!(object)
|
|
113
|
+
embed_object(object)
|
|
114
|
+
callback(:before_add, object)
|
|
115
|
+
|
|
108
116
|
association = self
|
|
109
117
|
|
|
110
118
|
object.define_create do
|
|
111
119
|
source = association.send(:read_source)
|
|
112
|
-
index = association.target
|
|
113
|
-
one.persisted? || one
|
|
114
|
-
|
|
120
|
+
index = association.target
|
|
121
|
+
.select { |one| one.persisted? || one.equal?(self) }
|
|
122
|
+
.index { |one| one.equal?(self) }
|
|
115
123
|
|
|
116
124
|
source.insert(index, attributes)
|
|
117
125
|
association.send(:write_source, source)
|
|
@@ -119,7 +127,7 @@ module ActiveData
|
|
|
119
127
|
|
|
120
128
|
object.define_update do
|
|
121
129
|
source = association.send(:read_source)
|
|
122
|
-
index = association.target.select(&:persisted?).index { |one| one
|
|
130
|
+
index = association.target.select(&:persisted?).index { |one| one.equal?(self) }
|
|
123
131
|
|
|
124
132
|
source[index] = attributes
|
|
125
133
|
association.send(:write_source, source)
|
|
@@ -127,11 +135,13 @@ module ActiveData
|
|
|
127
135
|
|
|
128
136
|
object.define_destroy do
|
|
129
137
|
source = association.send(:read_source)
|
|
130
|
-
index = association.target.select(&:persisted?).index { |one| one
|
|
138
|
+
index = association.target.select(&:persisted?).index { |one| one.equal?(self) }
|
|
131
139
|
|
|
132
140
|
source.delete_at(index) if index
|
|
133
141
|
association.send(:write_source, source)
|
|
134
142
|
end
|
|
143
|
+
|
|
144
|
+
callback(:after_add, object)
|
|
135
145
|
end
|
|
136
146
|
end
|
|
137
147
|
end
|
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
module ActiveData
|
|
2
2
|
module Model
|
|
3
3
|
module Associations
|
|
4
|
-
class EmbedsOne <
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
class EmbedsOne < EmbedsAny
|
|
5
|
+
attr_reader :destroyed
|
|
6
|
+
|
|
7
|
+
def build(attributes = {})
|
|
8
|
+
self.target = build_object(attributes)
|
|
7
9
|
end
|
|
8
10
|
|
|
9
|
-
def create
|
|
11
|
+
def create(attributes = {})
|
|
10
12
|
build(attributes).tap(&:save)
|
|
11
13
|
end
|
|
12
14
|
|
|
13
|
-
def create!
|
|
15
|
+
def create!(attributes = {})
|
|
14
16
|
build(attributes).tap(&:save!)
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
def destroyed
|
|
18
|
-
@destroyed
|
|
19
|
-
end
|
|
20
|
-
|
|
21
19
|
def apply_changes
|
|
22
20
|
if target
|
|
23
21
|
if target.destroyed? || target.marked_for_destruction?
|
|
@@ -31,10 +29,14 @@ module ActiveData
|
|
|
31
29
|
end
|
|
32
30
|
end
|
|
33
31
|
|
|
34
|
-
def target=
|
|
35
|
-
|
|
32
|
+
def target=(object)
|
|
33
|
+
if object
|
|
34
|
+
callback(:before_add, object)
|
|
35
|
+
setup_performers! object
|
|
36
|
+
end
|
|
36
37
|
loaded!
|
|
37
38
|
@target = object
|
|
39
|
+
callback(:after_add, object) if object
|
|
38
40
|
end
|
|
39
41
|
|
|
40
42
|
def load_target
|
|
@@ -43,20 +45,21 @@ module ActiveData
|
|
|
43
45
|
end
|
|
44
46
|
|
|
45
47
|
def default
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
object
|
|
48
|
+
return if evar_loaded?
|
|
49
|
+
|
|
50
|
+
default = reflection.default(owner)
|
|
51
|
+
|
|
52
|
+
return unless default
|
|
53
|
+
|
|
54
|
+
object = if default.is_a?(reflection.klass)
|
|
55
|
+
default
|
|
56
|
+
else
|
|
57
|
+
reflection.klass.with_sanitize(false) do
|
|
58
|
+
build_object(default)
|
|
58
59
|
end
|
|
59
60
|
end
|
|
61
|
+
object.send(:clear_changes_information) if reflection.klass.dirty?
|
|
62
|
+
object
|
|
60
63
|
end
|
|
61
64
|
|
|
62
65
|
def clear
|
|
@@ -64,12 +67,12 @@ module ActiveData
|
|
|
64
67
|
reload.nil?
|
|
65
68
|
end
|
|
66
69
|
|
|
67
|
-
def reader
|
|
70
|
+
def reader(force_reload = false)
|
|
68
71
|
reload if force_reload
|
|
69
72
|
target
|
|
70
73
|
end
|
|
71
74
|
|
|
72
|
-
def replace
|
|
75
|
+
def replace(object)
|
|
73
76
|
if object
|
|
74
77
|
raise AssociationTypeMismatch.new(reflection.klass, object.class) unless object.is_a?(reflection.klass)
|
|
75
78
|
transaction do
|
|
@@ -87,7 +90,8 @@ module ActiveData
|
|
|
87
90
|
|
|
88
91
|
private
|
|
89
92
|
|
|
90
|
-
def setup_performers!
|
|
93
|
+
def setup_performers!(object)
|
|
94
|
+
embed_object(object)
|
|
91
95
|
association = self
|
|
92
96
|
|
|
93
97
|
object.define_save do
|