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
|
@@ -11,27 +11,17 @@ module ActiveData
|
|
|
11
11
|
attr_accessor :parent_reflection
|
|
12
12
|
delegate :association_class, to: 'self.class'
|
|
13
13
|
|
|
14
|
-
def self.build
|
|
15
|
-
if block
|
|
16
|
-
options[:class] = proc do |reflection|
|
|
17
|
-
superclass = reflection.options[:class_name].to_s.presence.try(:constantize)
|
|
18
|
-
klass = Class.new(superclass || Object) do
|
|
19
|
-
include ActiveData::Model
|
|
20
|
-
include ActiveData::Model::Associations
|
|
21
|
-
include ActiveData::Model::Lifecycle
|
|
22
|
-
include ActiveData::Model::Primary
|
|
23
|
-
end
|
|
24
|
-
target.const_set(name.to_s.classify, klass)
|
|
25
|
-
klass.class_eval(&block)
|
|
26
|
-
klass
|
|
27
|
-
end
|
|
28
|
-
end
|
|
14
|
+
def self.build(target, generated_methods, name, options = {}, &_block)
|
|
29
15
|
generate_methods name, generated_methods
|
|
30
|
-
|
|
16
|
+
if options.delete(:validate) &&
|
|
17
|
+
target.respond_to?(:validates_nested) &&
|
|
18
|
+
!target.validates_nested?(name)
|
|
19
|
+
target.validates_nested name
|
|
20
|
+
end
|
|
31
21
|
new(name, options)
|
|
32
22
|
end
|
|
33
23
|
|
|
34
|
-
def self.generate_methods
|
|
24
|
+
def self.generate_methods(name, target)
|
|
35
25
|
target.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
36
26
|
def #{name} force_reload = false
|
|
37
27
|
association(:#{name}).reader(force_reload)
|
|
@@ -47,8 +37,9 @@ module ActiveData
|
|
|
47
37
|
@association_class ||= "ActiveData::Model::Associations::#{name.demodulize}".constantize
|
|
48
38
|
end
|
|
49
39
|
|
|
50
|
-
def initialize
|
|
51
|
-
@name
|
|
40
|
+
def initialize(name, options = {})
|
|
41
|
+
@name = name.to_sym
|
|
42
|
+
@options = options
|
|
52
43
|
end
|
|
53
44
|
|
|
54
45
|
def macro
|
|
@@ -56,31 +47,30 @@ module ActiveData
|
|
|
56
47
|
end
|
|
57
48
|
|
|
58
49
|
def klass
|
|
59
|
-
@klass ||= options[:
|
|
60
|
-
options[:class].call(self) :
|
|
61
|
-
(options[:class_name].presence || name.to_s.classify).to_s.constantize
|
|
50
|
+
@klass ||= (options[:class_name].presence || name.to_s.classify).to_s.constantize
|
|
62
51
|
end
|
|
63
52
|
|
|
53
|
+
# AR compatibility
|
|
64
54
|
def belongs_to?
|
|
65
55
|
false
|
|
66
56
|
end
|
|
67
57
|
|
|
68
|
-
def build_association
|
|
58
|
+
def build_association(object)
|
|
69
59
|
self.class.association_class.new object, self
|
|
70
60
|
end
|
|
71
61
|
|
|
72
|
-
def read_source
|
|
62
|
+
def read_source(object)
|
|
73
63
|
(options[:read] || READ).call(self, object)
|
|
74
64
|
end
|
|
75
65
|
|
|
76
|
-
def write_source
|
|
66
|
+
def write_source(object, value)
|
|
77
67
|
(options[:write] || WRITE).call(self, object, value)
|
|
78
68
|
end
|
|
79
69
|
|
|
80
|
-
def default
|
|
70
|
+
def default(object)
|
|
81
71
|
defaultizer = options[:default]
|
|
82
72
|
if defaultizer.is_a?(Proc)
|
|
83
|
-
if defaultizer.arity
|
|
73
|
+
if defaultizer.arity.nonzero?
|
|
84
74
|
defaultizer.call(object)
|
|
85
75
|
else
|
|
86
76
|
object.instance_exec(&defaultizer)
|
|
@@ -90,8 +80,8 @@ module ActiveData
|
|
|
90
80
|
end
|
|
91
81
|
end
|
|
92
82
|
|
|
93
|
-
def
|
|
94
|
-
|
|
83
|
+
def collection?
|
|
84
|
+
true
|
|
95
85
|
end
|
|
96
86
|
end
|
|
97
87
|
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module ActiveData
|
|
2
|
+
module Model
|
|
3
|
+
module Associations
|
|
4
|
+
module Reflections
|
|
5
|
+
class EmbedsAny < Base
|
|
6
|
+
def self.build(target, generated_methods, name, options = {}, &block)
|
|
7
|
+
if block
|
|
8
|
+
options[:class] = proc do |reflection|
|
|
9
|
+
superclass = reflection.options[:class_name].to_s.presence.try(:constantize)
|
|
10
|
+
klass = Class.new(superclass || ActiveData::Base) do
|
|
11
|
+
include ActiveData::Model
|
|
12
|
+
include ActiveData::Model::Associations
|
|
13
|
+
include ActiveData::Model::Lifecycle
|
|
14
|
+
include ActiveData::Model::Primary
|
|
15
|
+
end
|
|
16
|
+
target.const_set(name.to_s.classify, klass)
|
|
17
|
+
klass.class_eval(&block)
|
|
18
|
+
klass
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
super
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def klass
|
|
25
|
+
@klass ||= if options[:class]
|
|
26
|
+
options[:class].call(self)
|
|
27
|
+
else
|
|
28
|
+
super
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def inspect
|
|
33
|
+
"#{self.class.name.demodulize}(#{klass})"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def embedded?
|
|
37
|
+
true
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -2,22 +2,12 @@ module ActiveData
|
|
|
2
2
|
module Model
|
|
3
3
|
module Associations
|
|
4
4
|
module Reflections
|
|
5
|
-
class EmbedsMany <
|
|
6
|
-
def self.build
|
|
7
|
-
if target < ActiveData::Model::Attributes
|
|
8
|
-
target.add_attribute(ActiveData::Model::Attributes::Reflections::Base, name)
|
|
9
|
-
end
|
|
5
|
+
class EmbedsMany < EmbedsAny
|
|
6
|
+
def self.build(target, generated_methods, name, options = {}, &block)
|
|
7
|
+
target.add_attribute(ActiveData::Model::Attributes::Reflections::Base, name) if target < ActiveData::Model::Attributes
|
|
10
8
|
options[:validate] = true unless options.key?(:validate)
|
|
11
9
|
super
|
|
12
10
|
end
|
|
13
|
-
|
|
14
|
-
def collection?
|
|
15
|
-
true
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def embedded?
|
|
19
|
-
true
|
|
20
|
-
end
|
|
21
11
|
end
|
|
22
12
|
end
|
|
23
13
|
end
|
|
@@ -2,46 +2,14 @@ module ActiveData
|
|
|
2
2
|
module Model
|
|
3
3
|
module Associations
|
|
4
4
|
module Reflections
|
|
5
|
-
class EmbedsOne <
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
class EmbedsOne < EmbedsAny
|
|
6
|
+
include Singular
|
|
7
|
+
|
|
8
|
+
def self.build(target, generated_methods, name, options = {}, &block)
|
|
9
|
+
target.add_attribute(ActiveData::Model::Attributes::Reflections::Base, name) if target < ActiveData::Model::Attributes
|
|
10
10
|
options[:validate] = true unless options.key?(:validate)
|
|
11
11
|
super
|
|
12
12
|
end
|
|
13
|
-
|
|
14
|
-
def self.generate_methods name, target
|
|
15
|
-
target.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
16
|
-
def #{name} force_reload = false
|
|
17
|
-
association(:#{name}).reader(force_reload)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def #{name}= value
|
|
21
|
-
association(:#{name}).writer(value)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def build_#{name} attributes = {}
|
|
25
|
-
association(:#{name}).build(attributes)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def create_#{name} attributes = {}
|
|
29
|
-
association(:#{name}).create(attributes)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def create_#{name}! attributes = {}
|
|
33
|
-
association(:#{name}).create!(attributes)
|
|
34
|
-
end
|
|
35
|
-
RUBY
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def collection?
|
|
39
|
-
false
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def embedded?
|
|
43
|
-
true
|
|
44
|
-
end
|
|
45
13
|
end
|
|
46
14
|
end
|
|
47
15
|
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module ActiveData
|
|
2
|
+
module Model
|
|
3
|
+
module Associations
|
|
4
|
+
module Reflections
|
|
5
|
+
class ReferencesAny < Base
|
|
6
|
+
def self.build(_target, generated_methods, name, *args)
|
|
7
|
+
reflection = new(name, *args)
|
|
8
|
+
generate_methods name, generated_methods
|
|
9
|
+
reflection
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.persistence_adapter(klass)
|
|
13
|
+
adapter = klass.active_data_persistence_adapter if klass.respond_to?(:active_data_persistence_adapter)
|
|
14
|
+
adapter or raise PersistenceAdapterMissing, klass
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
delegate :primary_key, to: :persistence_adapter
|
|
18
|
+
|
|
19
|
+
def initialize(name, *args)
|
|
20
|
+
@options = args.extract_options!
|
|
21
|
+
@scope_proc = args.first
|
|
22
|
+
@name = name.to_sym
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def klass
|
|
26
|
+
@klass ||= if options[:data_source].present?
|
|
27
|
+
options[:data_source].to_s.constantize
|
|
28
|
+
else
|
|
29
|
+
super
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
alias_method :data_source, :klass
|
|
33
|
+
|
|
34
|
+
def persistence_adapter
|
|
35
|
+
@persistence_adapter ||= self.class.persistence_adapter(klass)
|
|
36
|
+
.new(data_source, options[:primary_key], @scope_proc)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def read_source(object)
|
|
40
|
+
object.read_attribute(reference_key)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def write_source(object, value)
|
|
44
|
+
object.write_attribute(reference_key, value)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def embedded?
|
|
48
|
+
false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def inspect
|
|
52
|
+
"#{self.class.name.demodulize}(#{persistence_adapter.data_type})"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def autosave?
|
|
56
|
+
!!options[:autosave]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
+
require 'active_data/model/attributes/reflections/reference_many'
|
|
2
|
+
require 'active_data/model/attributes/reference_many'
|
|
3
|
+
|
|
1
4
|
module ActiveData
|
|
2
5
|
module Model
|
|
3
6
|
module Associations
|
|
4
7
|
module Reflections
|
|
5
|
-
class ReferencesMany <
|
|
6
|
-
def self.build
|
|
8
|
+
class ReferencesMany < ReferencesAny
|
|
9
|
+
def self.build(target, generated_methods, name, *args, &block)
|
|
7
10
|
reflection = super
|
|
8
11
|
|
|
9
12
|
target.add_attribute(
|
|
10
13
|
ActiveData::Model::Attributes::Reflections::ReferenceMany,
|
|
11
|
-
reflection.reference_key, association: name
|
|
14
|
+
reflection.reference_key, association: name
|
|
15
|
+
)
|
|
12
16
|
|
|
13
17
|
reflection
|
|
14
18
|
end
|
|
15
19
|
|
|
16
|
-
def collection?
|
|
17
|
-
true
|
|
18
|
-
end
|
|
19
|
-
|
|
20
20
|
def reference_key
|
|
21
21
|
@reference_key ||= options[:reference_key].presence.try(:to_sym) ||
|
|
22
22
|
:"#{name.to_s.singularize}_#{primary_key.to_s.pluralize}"
|
|
@@ -1,22 +1,24 @@
|
|
|
1
|
+
require 'active_data/model/attributes/reflections/reference_one'
|
|
2
|
+
require 'active_data/model/attributes/reference_one'
|
|
3
|
+
|
|
1
4
|
module ActiveData
|
|
2
5
|
module Model
|
|
3
6
|
module Associations
|
|
4
7
|
module Reflections
|
|
5
|
-
class ReferencesOne <
|
|
6
|
-
|
|
8
|
+
class ReferencesOne < ReferencesAny
|
|
9
|
+
include Singular
|
|
10
|
+
|
|
11
|
+
def self.build(target, generated_methods, name, *args, &block)
|
|
7
12
|
reflection = super
|
|
8
13
|
|
|
9
14
|
target.add_attribute(
|
|
10
15
|
ActiveData::Model::Attributes::Reflections::ReferenceOne,
|
|
11
|
-
reflection.reference_key, association: name
|
|
16
|
+
reflection.reference_key, association: name
|
|
17
|
+
)
|
|
12
18
|
|
|
13
19
|
reflection
|
|
14
20
|
end
|
|
15
21
|
|
|
16
|
-
def collection?
|
|
17
|
-
false
|
|
18
|
-
end
|
|
19
|
-
|
|
20
22
|
def reference_key
|
|
21
23
|
@reference_key ||= options[:reference_key].presence.try(:to_sym) ||
|
|
22
24
|
:"#{name}_#{primary_key}"
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module ActiveData
|
|
2
|
+
module Model
|
|
3
|
+
module Associations
|
|
4
|
+
module Reflections
|
|
5
|
+
module Singular
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
def generate_methods(name, target)
|
|
10
|
+
super
|
|
11
|
+
|
|
12
|
+
target.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
13
|
+
def build_#{name} attributes = {}
|
|
14
|
+
association(:#{name}).build(attributes)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def create_#{name} attributes = {}
|
|
18
|
+
association(:#{name}).create(attributes)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def create_#{name}! attributes = {}
|
|
22
|
+
association(:#{name}).create!(attributes)
|
|
23
|
+
end
|
|
24
|
+
RUBY
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def collection?
|
|
29
|
+
false
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -19,44 +19,19 @@ module ActiveData
|
|
|
19
19
|
|
|
20
20
|
private
|
|
21
21
|
|
|
22
|
-
def run_validations! #:nodoc:
|
|
23
|
-
super
|
|
24
|
-
emerge_represented_attributes_errors!
|
|
25
|
-
errors.empty?
|
|
26
|
-
end
|
|
27
|
-
|
|
28
22
|
def validate_nested!
|
|
29
23
|
association_names.each do |name|
|
|
30
24
|
association = association(name)
|
|
31
25
|
invalid_block = if association.reflection.klass.method_defined?(:invalid_ansestry?)
|
|
32
|
-
|
|
26
|
+
->(object) { object.invalid_ansestry? }
|
|
33
27
|
else
|
|
34
|
-
|
|
28
|
+
->(object) { object.invalid? }
|
|
35
29
|
end
|
|
36
30
|
|
|
37
31
|
ActiveData::Model::Validations::NestedValidator
|
|
38
32
|
.validate_nested(self, name, association.target, &invalid_block)
|
|
39
33
|
end
|
|
40
34
|
end
|
|
41
|
-
|
|
42
|
-
# Move represent attribute errors to the top level:
|
|
43
|
-
#
|
|
44
|
-
# {:'role.email' => ['Some error']}
|
|
45
|
-
#
|
|
46
|
-
# to:
|
|
47
|
-
#
|
|
48
|
-
# {email: ['Some error']}
|
|
49
|
-
#
|
|
50
|
-
def emerge_represented_attributes_errors!
|
|
51
|
-
self.class.represented_attributes.each do |attribute|
|
|
52
|
-
key = :"#{attribute.reference}.#{attribute.column}"
|
|
53
|
-
messages = errors.messages[key]
|
|
54
|
-
if messages.present?
|
|
55
|
-
errors[attribute.column].concat(messages)
|
|
56
|
-
errors.delete(key)
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
35
|
end
|
|
61
36
|
end
|
|
62
37
|
end
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
require 'active_data/model/associations/collection/proxy'
|
|
2
2
|
require 'active_data/model/associations/collection/embedded'
|
|
3
|
-
require 'active_data/model/associations/collection/referenced'
|
|
4
3
|
|
|
5
4
|
require 'active_data/model/associations/reflections/base'
|
|
5
|
+
require 'active_data/model/associations/reflections/singular'
|
|
6
|
+
require 'active_data/model/associations/reflections/embeds_any'
|
|
6
7
|
require 'active_data/model/associations/reflections/embeds_one'
|
|
7
8
|
require 'active_data/model/associations/reflections/embeds_many'
|
|
8
|
-
require 'active_data/model/associations/reflections/
|
|
9
|
+
require 'active_data/model/associations/reflections/references_any'
|
|
9
10
|
require 'active_data/model/associations/reflections/references_one'
|
|
10
11
|
require 'active_data/model/associations/reflections/references_many'
|
|
11
12
|
|
|
12
13
|
require 'active_data/model/associations/base'
|
|
14
|
+
require 'active_data/model/associations/embeds_any'
|
|
13
15
|
require 'active_data/model/associations/embeds_one'
|
|
14
16
|
require 'active_data/model/associations/embeds_many'
|
|
17
|
+
require 'active_data/model/associations/references_any'
|
|
15
18
|
require 'active_data/model/associations/references_one'
|
|
16
19
|
require 'active_data/model/associations/references_many'
|
|
17
20
|
|
|
@@ -25,7 +28,6 @@ module ActiveData
|
|
|
25
28
|
|
|
26
29
|
included do
|
|
27
30
|
include NestedAttributes
|
|
28
|
-
include Validations
|
|
29
31
|
|
|
30
32
|
class_attribute :_associations, :_association_aliases, instance_reader: false, instance_writer: false
|
|
31
33
|
self._associations = {}
|
|
@@ -54,13 +56,13 @@ module ActiveData
|
|
|
54
56
|
|
|
55
57
|
def alias_association(alias_name, association_name)
|
|
56
58
|
reflection = reflect_on_association(association_name)
|
|
57
|
-
raise ArgumentError
|
|
59
|
+
raise ArgumentError, "Can't alias undefined association `#{attribute_name}` on #{self}" unless reflection
|
|
58
60
|
reflection.class.generate_methods alias_name, generated_associations_methods
|
|
59
61
|
self._association_aliases = _association_aliases.merge(alias_name.to_sym => reflection.name)
|
|
60
62
|
reflection
|
|
61
63
|
end
|
|
62
64
|
|
|
63
|
-
def reflect_on_association
|
|
65
|
+
def reflect_on_association(name)
|
|
64
66
|
name = name.to_sym
|
|
65
67
|
_associations[_association_aliases[name] || name]
|
|
66
68
|
end
|
|
@@ -83,17 +85,17 @@ module ActiveData
|
|
|
83
85
|
end
|
|
84
86
|
end
|
|
85
87
|
|
|
86
|
-
def ==
|
|
88
|
+
def ==(other)
|
|
87
89
|
super && association_names.all? do |association|
|
|
88
90
|
public_send(association) == other.public_send(association)
|
|
89
91
|
end
|
|
90
92
|
end
|
|
91
93
|
alias_method :eql?, :==
|
|
92
94
|
|
|
93
|
-
def association
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
def association(name)
|
|
96
|
+
reflection = self.class.reflect_on_association(name)
|
|
97
|
+
return unless reflection
|
|
98
|
+
(@_associations ||= {})[reflection.name] ||= reflection.build_association(self)
|
|
97
99
|
end
|
|
98
100
|
|
|
99
101
|
def apply_association_changes!
|
|
@@ -4,7 +4,7 @@ module ActiveData
|
|
|
4
4
|
class Attribute < Base
|
|
5
5
|
delegate :defaultizer, :enumerizer, :normalizers, to: :reflection
|
|
6
6
|
|
|
7
|
-
def write
|
|
7
|
+
def write(value)
|
|
8
8
|
return if readonly?
|
|
9
9
|
pollute do
|
|
10
10
|
write_value value
|
|
@@ -27,8 +27,8 @@ module ActiveData
|
|
|
27
27
|
defaultizer.is_a?(Proc) ? evaluate(&defaultizer) : defaultizer
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
def defaultize
|
|
31
|
-
defaultizer && value.nil? ? default_value || default : value
|
|
30
|
+
def defaultize(value, default_value = nil)
|
|
31
|
+
!defaultizer.nil? && value.nil? ? default_value || default : value
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def enum
|
|
@@ -44,25 +44,25 @@ module ActiveData
|
|
|
44
44
|
end.to_set
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
def enumerize
|
|
47
|
+
def enumerize(value)
|
|
48
48
|
set = enum if enumerizer
|
|
49
49
|
value if !set || (set.none? || set.include?(value))
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
def normalize
|
|
52
|
+
def normalize(value)
|
|
53
53
|
if normalizers.none?
|
|
54
54
|
value
|
|
55
55
|
else
|
|
56
|
-
normalizers.inject(value) do |
|
|
56
|
+
normalizers.inject(value) do |val, normalizer|
|
|
57
57
|
case normalizer
|
|
58
58
|
when Proc
|
|
59
|
-
evaluate(
|
|
59
|
+
evaluate(val, &normalizer)
|
|
60
60
|
when Hash
|
|
61
|
-
normalizer.inject(
|
|
62
|
-
ActiveData.normalizer(name).call(
|
|
61
|
+
normalizer.inject(val) do |v, (name, options)|
|
|
62
|
+
ActiveData.normalizer(name).call(v, options, self)
|
|
63
63
|
end
|
|
64
64
|
else
|
|
65
|
-
ActiveData.normalizer(normalizer).call(
|
|
65
|
+
ActiveData.normalizer(normalizer).call(val, {}, self)
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
end
|
|
@@ -5,20 +5,21 @@ module ActiveData
|
|
|
5
5
|
attr_reader :name, :owner
|
|
6
6
|
delegate :type, :typecaster, :readonly, to: :reflection
|
|
7
7
|
|
|
8
|
-
def initialize
|
|
9
|
-
@name
|
|
8
|
+
def initialize(name, owner)
|
|
9
|
+
@name = name
|
|
10
|
+
@owner = owner
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
def reflection
|
|
13
14
|
@owner.class._attributes[name]
|
|
14
15
|
end
|
|
15
16
|
|
|
16
|
-
def write_value
|
|
17
|
+
def write_value(value)
|
|
17
18
|
reset
|
|
18
19
|
@value_cache = value
|
|
19
20
|
end
|
|
20
21
|
|
|
21
|
-
def write
|
|
22
|
+
def write(value)
|
|
22
23
|
return if readonly?
|
|
23
24
|
write_value value
|
|
24
25
|
end
|
|
@@ -43,7 +44,7 @@ module ActiveData
|
|
|
43
44
|
!(read.respond_to?(:zero?) ? read.zero? : read.blank?)
|
|
44
45
|
end
|
|
45
46
|
|
|
46
|
-
def typecast
|
|
47
|
+
def typecast(value)
|
|
47
48
|
if value.instance_of?(type)
|
|
48
49
|
value
|
|
49
50
|
else
|
|
@@ -86,12 +87,12 @@ module ActiveData
|
|
|
86
87
|
|
|
87
88
|
private
|
|
88
89
|
|
|
89
|
-
def evaluate
|
|
90
|
+
def evaluate(*args, &block)
|
|
90
91
|
if block.arity >= 0 && block.arity <= args.length
|
|
91
92
|
owner.instance_exec(*args.first(block.arity), &block)
|
|
92
93
|
else
|
|
93
94
|
args = block.arity < 0 ? args : args.first(block.arity)
|
|
94
|
-
|
|
95
|
+
yield(*args, owner)
|
|
95
96
|
end
|
|
96
97
|
end
|
|
97
98
|
|
|
@@ -14,25 +14,25 @@ module ActiveData
|
|
|
14
14
|
end]
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def write_locale
|
|
17
|
+
def write_locale(value, locale)
|
|
18
18
|
pollute do
|
|
19
19
|
write(read.merge(locale.to_s => value))
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def read_locale
|
|
23
|
+
def read_locale(locale)
|
|
24
24
|
read[owner.class.fallbacks(locale).detect do |fallback|
|
|
25
25
|
read[fallback.to_s]
|
|
26
26
|
end.to_s]
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def read_locale_before_type_cast
|
|
29
|
+
def read_locale_before_type_cast(locale)
|
|
30
30
|
read_before_type_cast[owner.class.fallbacks(locale).detect do |fallback|
|
|
31
31
|
read_before_type_cast[fallback.to_s]
|
|
32
32
|
end.to_s]
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
def locale_query
|
|
35
|
+
def locale_query(locale)
|
|
36
36
|
value = read_locale(locale)
|
|
37
37
|
!(value.respond_to?(:zero?) ? value.zero? : value.blank?)
|
|
38
38
|
end
|
|
@@ -2,19 +2,17 @@ module ActiveData
|
|
|
2
2
|
module Model
|
|
3
3
|
module Attributes
|
|
4
4
|
class ReferenceMany < ReferenceOne
|
|
5
|
-
def read_before_type_cast
|
|
6
|
-
variable_cache(:value_before_type_cast) do
|
|
7
|
-
Array.wrap(@value_cache)
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
private
|
|
12
|
-
|
|
13
5
|
def type_casted_value
|
|
14
6
|
variable_cache(:value) do
|
|
15
7
|
read_before_type_cast.map { |id| typecast(id) }
|
|
16
8
|
end
|
|
17
9
|
end
|
|
10
|
+
|
|
11
|
+
def read_before_type_cast
|
|
12
|
+
variable_cache(:value_before_type_cast) do
|
|
13
|
+
Array.wrap(@value_cache)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
18
16
|
end
|
|
19
17
|
end
|
|
20
18
|
end
|