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
|
@@ -2,13 +2,13 @@ module ActiveData
|
|
|
2
2
|
module Model
|
|
3
3
|
module Attributes
|
|
4
4
|
class ReferenceOne < Base
|
|
5
|
-
def write
|
|
5
|
+
def write(value)
|
|
6
6
|
pollute do
|
|
7
7
|
previous = type_casted_value
|
|
8
8
|
result = write_value value
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
changed = (!value.nil? && type_casted_value.nil?) || type_casted_value != previous
|
|
10
|
+
|
|
11
|
+
association.reset if changed
|
|
12
12
|
result
|
|
13
13
|
end
|
|
14
14
|
end
|
|
@@ -21,18 +21,26 @@ module ActiveData
|
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
def type_casted_value
|
|
25
|
+
variable_cache(:value) do
|
|
26
|
+
typecast(read_before_type_cast)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
24
30
|
def read_before_type_cast
|
|
25
31
|
@value_cache
|
|
26
32
|
end
|
|
27
33
|
|
|
28
|
-
|
|
34
|
+
def type
|
|
35
|
+
@type ||= association.reflection.persistence_adapter.primary_key_type
|
|
36
|
+
end
|
|
29
37
|
|
|
30
|
-
def
|
|
31
|
-
|
|
32
|
-
typecast(read_before_type_cast)
|
|
33
|
-
end
|
|
38
|
+
def typecaster
|
|
39
|
+
@typecaster ||= ActiveData.typecaster(type.ancestors.grep(Class))
|
|
34
40
|
end
|
|
35
41
|
|
|
42
|
+
private
|
|
43
|
+
|
|
36
44
|
def association
|
|
37
45
|
@association ||= owner.association(reflection.association)
|
|
38
46
|
end
|
|
@@ -3,13 +3,13 @@ module ActiveData
|
|
|
3
3
|
module Attributes
|
|
4
4
|
module Reflections
|
|
5
5
|
class Attribute < Base
|
|
6
|
-
def self.build
|
|
6
|
+
def self.build(target, generated_methods, name, *args, &block)
|
|
7
7
|
attribute = super(target, generated_methods, name, *args, &block)
|
|
8
8
|
generate_methods name, generated_methods
|
|
9
9
|
attribute
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def self.generate_methods
|
|
12
|
+
def self.generate_methods(name, target)
|
|
13
13
|
target.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
14
14
|
def #{name}
|
|
15
15
|
attribute('#{name}').read
|
|
@@ -5,37 +5,34 @@ module ActiveData
|
|
|
5
5
|
class Base
|
|
6
6
|
attr_reader :name, :options
|
|
7
7
|
class << self
|
|
8
|
-
def build
|
|
8
|
+
def build(_target, _generated_methods, name, *args, &block)
|
|
9
9
|
options = args.extract_options!
|
|
10
|
-
options
|
|
11
|
-
options
|
|
10
|
+
options[:type] = args.first if args.first
|
|
11
|
+
options[:default] = block if block
|
|
12
12
|
new(name, options)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
-
def generate_methods
|
|
16
|
-
end
|
|
15
|
+
def generate_methods(name, target) end
|
|
17
16
|
|
|
18
17
|
def attribute_class
|
|
19
18
|
@attribute_class ||= "ActiveData::Model::Attributes::#{name.demodulize}".constantize
|
|
20
19
|
end
|
|
21
20
|
end
|
|
22
21
|
|
|
23
|
-
def initialize
|
|
22
|
+
def initialize(name, options = {})
|
|
24
23
|
@name = name.to_s
|
|
25
24
|
@options = options
|
|
26
25
|
end
|
|
27
26
|
|
|
28
|
-
def build_attribute
|
|
27
|
+
def build_attribute(owner, raw_value = ActiveData::UNDEFINED)
|
|
29
28
|
attribute = self.class.attribute_class.new(name, owner)
|
|
30
|
-
attribute.write_value(raw_value)
|
|
29
|
+
attribute.write_value(raw_value) unless raw_value == ActiveData::UNDEFINED
|
|
31
30
|
attribute
|
|
32
31
|
end
|
|
33
32
|
|
|
34
33
|
def type
|
|
35
34
|
@type ||= case options[:type]
|
|
36
|
-
when
|
|
37
|
-
options[:type].call
|
|
38
|
-
when Class
|
|
35
|
+
when Class, Module
|
|
39
36
|
options[:type]
|
|
40
37
|
when nil
|
|
41
38
|
raise "Type is not specified for `#{name}`"
|
|
@@ -3,13 +3,13 @@ module ActiveData
|
|
|
3
3
|
module Attributes
|
|
4
4
|
module Reflections
|
|
5
5
|
class Localized < Attribute
|
|
6
|
-
def self.build
|
|
6
|
+
def self.build(target, generated_methods, name, *args, &block)
|
|
7
7
|
attribute = super(target, generated_methods, name, *args, &block)
|
|
8
8
|
generate_methods name, generated_methods
|
|
9
9
|
attribute
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def self.generate_methods
|
|
12
|
+
def self.generate_methods(name, target)
|
|
13
13
|
target.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
14
14
|
def #{name}_translations
|
|
15
15
|
attribute('#{name}').read
|
|
@@ -3,32 +3,13 @@ module ActiveData
|
|
|
3
3
|
module Attributes
|
|
4
4
|
module Reflections
|
|
5
5
|
class ReferenceOne < Base
|
|
6
|
-
|
|
7
|
-
integer: Integer,
|
|
8
|
-
float: Float,
|
|
9
|
-
decimal: BigDecimal,
|
|
10
|
-
datetime: Time,
|
|
11
|
-
timestamp: Time,
|
|
12
|
-
time: Time,
|
|
13
|
-
date: Date,
|
|
14
|
-
text: String,
|
|
15
|
-
string: String,
|
|
16
|
-
binary: String,
|
|
17
|
-
boolean: Boolean
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
def self.build target, generated_methods, name, *args, &block
|
|
6
|
+
def self.build(_target, generated_methods, name, *args)
|
|
21
7
|
options = args.extract_options!
|
|
22
8
|
generate_methods name, generated_methods
|
|
23
|
-
|
|
24
|
-
reflection = target.reflect_on_association(options[:association])
|
|
25
|
-
column = reflection.klass.columns_hash[reflection.primary_key.to_s]
|
|
26
|
-
TYPES[column.type]
|
|
27
|
-
}
|
|
28
|
-
new(name, options.reverse_merge(type: type_proc))
|
|
9
|
+
new(name, options)
|
|
29
10
|
end
|
|
30
11
|
|
|
31
|
-
def self.generate_methods
|
|
12
|
+
def self.generate_methods(name, target)
|
|
32
13
|
target.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
33
14
|
def #{name}
|
|
34
15
|
attribute('#{name}').read
|
|
@@ -48,6 +29,14 @@ module ActiveData
|
|
|
48
29
|
RUBY
|
|
49
30
|
end
|
|
50
31
|
|
|
32
|
+
def type
|
|
33
|
+
Object
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def inspect_reflection
|
|
37
|
+
"#{name}: (reference)"
|
|
38
|
+
end
|
|
39
|
+
|
|
51
40
|
def association
|
|
52
41
|
@association ||= options[:association].to_s
|
|
53
42
|
end
|
|
@@ -3,20 +3,19 @@ module ActiveData
|
|
|
3
3
|
module Attributes
|
|
4
4
|
module Reflections
|
|
5
5
|
class Represents < Attribute
|
|
6
|
-
def self.build
|
|
6
|
+
def self.build(target, generated_methods, name, *args, &block)
|
|
7
7
|
options = args.extract_options!
|
|
8
8
|
|
|
9
9
|
reference = target.reflect_on_association(options[:of]) if target.respond_to?(:reflect_on_association)
|
|
10
10
|
reference ||= target.reflect_on_attribute(options[:of]) if target.respond_to?(:reflect_on_attribute)
|
|
11
|
-
if reference
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
end
|
|
11
|
+
options[:of] = reference.name if reference
|
|
12
|
+
validates_nested = target.respond_to?(:validates_nested) && !target.validates_nested?(options[:of])
|
|
13
|
+
target.validates_nested(options[:of]) if validates_nested
|
|
15
14
|
|
|
16
15
|
super(target, generated_methods, name, *args, options, &block)
|
|
17
16
|
end
|
|
18
17
|
|
|
19
|
-
def initialize
|
|
18
|
+
def initialize(name, options)
|
|
20
19
|
super
|
|
21
20
|
raise ArgumentError, "Undefined reference for `#{name}`" if reference.blank?
|
|
22
21
|
end
|
|
@@ -4,7 +4,7 @@ module ActiveData
|
|
|
4
4
|
class Represents < Attribute
|
|
5
5
|
delegate :reader, :reader_before_type_cast, :writer, to: :reflection
|
|
6
6
|
|
|
7
|
-
def write
|
|
7
|
+
def write(value)
|
|
8
8
|
return if readonly?
|
|
9
9
|
pollute do
|
|
10
10
|
reset
|
|
@@ -48,10 +48,11 @@ module ActiveData
|
|
|
48
48
|
|
|
49
49
|
def read_value_before_type_cast
|
|
50
50
|
ref = reference
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
return unless ref
|
|
52
|
+
if ref.respond_to?(reader_before_type_cast)
|
|
53
|
+
ref.public_send(reader_before_type_cast)
|
|
54
|
+
else
|
|
55
|
+
ref.public_send(reader)
|
|
55
56
|
end
|
|
56
57
|
end
|
|
57
58
|
|
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
require 'active_data/model/attributes/reflections/base'
|
|
2
|
-
require 'active_data/model/attributes/reflections/reference_one'
|
|
3
|
-
require 'active_data/model/attributes/reflections/reference_many'
|
|
4
2
|
require 'active_data/model/attributes/reflections/attribute'
|
|
5
3
|
require 'active_data/model/attributes/reflections/collection'
|
|
6
4
|
require 'active_data/model/attributes/reflections/dictionary'
|
|
7
|
-
require 'active_data/model/attributes/reflections/localized'
|
|
8
|
-
require 'active_data/model/attributes/reflections/represents'
|
|
9
5
|
|
|
10
6
|
require 'active_data/model/attributes/base'
|
|
11
|
-
require 'active_data/model/attributes/reference_one'
|
|
12
|
-
require 'active_data/model/attributes/reference_many'
|
|
13
7
|
require 'active_data/model/attributes/attribute'
|
|
14
8
|
require 'active_data/model/attributes/collection'
|
|
15
9
|
require 'active_data/model/attributes/dictionary'
|
|
16
|
-
require 'active_data/model/attributes/localized'
|
|
17
|
-
require 'active_data/model/attributes/represents'
|
|
18
10
|
|
|
19
11
|
module ActiveData
|
|
20
12
|
module Model
|
|
@@ -37,31 +29,21 @@ module ActiveData
|
|
|
37
29
|
end
|
|
38
30
|
|
|
39
31
|
module ClassMethods
|
|
40
|
-
def represents(*names, &block)
|
|
41
|
-
options = names.extract_options!
|
|
42
|
-
names.each do |name|
|
|
43
|
-
add_attribute(Reflections::Represents, name, options, &block)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
32
|
def add_attribute(reflection_class, *args, &block)
|
|
48
33
|
reflection = reflection_class.build(self, generated_attributes_methods, *args, &block)
|
|
49
34
|
self._attributes = _attributes.merge(reflection.name => reflection)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
end
|
|
35
|
+
should_define_dirty = (dirty? && reflection_class != ActiveData::Model::Attributes::Reflections::Base)
|
|
36
|
+
define_dirty(reflection.name, generated_attributes_methods) if should_define_dirty
|
|
53
37
|
reflection
|
|
54
38
|
end
|
|
55
39
|
|
|
56
40
|
def alias_attribute(alias_name, attribute_name)
|
|
57
41
|
reflection = reflect_on_attribute(attribute_name)
|
|
58
|
-
raise ArgumentError
|
|
59
|
-
raise ArgumentError
|
|
42
|
+
raise ArgumentError, "Unable to alias undefined attribute `#{attribute_name}` on #{self}" unless reflection
|
|
43
|
+
raise ArgumentError, "Unable to alias base attribute `#{attribute_name}`" if reflection.class == ActiveData::Model::Attributes::Reflections::Base
|
|
60
44
|
reflection.class.generate_methods alias_name, generated_attributes_methods
|
|
61
45
|
self._attribute_aliases = _attribute_aliases.merge(alias_name.to_s => reflection.name)
|
|
62
|
-
if dirty?
|
|
63
|
-
define_dirty alias_name, generated_attributes_methods
|
|
64
|
-
end
|
|
46
|
+
define_dirty alias_name, generated_attributes_methods if dirty?
|
|
65
47
|
reflection
|
|
66
48
|
end
|
|
67
49
|
|
|
@@ -70,7 +52,7 @@ module ActiveData
|
|
|
70
52
|
_attributes[_attribute_aliases[name] || name]
|
|
71
53
|
end
|
|
72
54
|
|
|
73
|
-
def has_attribute?
|
|
55
|
+
def has_attribute?(name) # rubocop:disable Naming/PredicateName
|
|
74
56
|
name = name.to_s
|
|
75
57
|
_attributes.key?(_attribute_aliases[name] || name)
|
|
76
58
|
end
|
|
@@ -89,24 +71,13 @@ module ActiveData
|
|
|
89
71
|
"#{original_inspect}(#{attributes_for_inspect.presence || 'no attributes'})"
|
|
90
72
|
end
|
|
91
73
|
|
|
92
|
-
def represented_attributes
|
|
93
|
-
@represented_attributes ||= _attributes.values.select do |attribute|
|
|
94
|
-
attribute.is_a? ActiveData::Model::Attributes::Reflections::Represents
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
def represented_names_and_aliases
|
|
99
|
-
@represented_names_and_aliases ||= represented_attributes.flat_map do |attribute|
|
|
100
|
-
[attribute.name, *inverted_attribute_aliases[attribute.name]]
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
74
|
def dirty?
|
|
105
75
|
false
|
|
106
76
|
end
|
|
107
77
|
|
|
108
78
|
def with_sanitize(value)
|
|
109
|
-
previous_sanitize
|
|
79
|
+
previous_sanitize = _sanitize
|
|
80
|
+
self._sanitize = value
|
|
110
81
|
yield
|
|
111
82
|
ensure
|
|
112
83
|
self._sanitize = previous_sanitize
|
|
@@ -120,7 +91,7 @@ module ActiveData
|
|
|
120
91
|
|
|
121
92
|
def attributes_for_inspect
|
|
122
93
|
attribute_names(false).map do |name|
|
|
123
|
-
prefix = respond_to?(:_primary_name) && _primary_name == name ?
|
|
94
|
+
prefix = respond_to?(:_primary_name) && _primary_name == name ? '*' : ''
|
|
124
95
|
"#{prefix}#{_attributes[name].inspect_reflection}"
|
|
125
96
|
end.join(', ')
|
|
126
97
|
end
|
|
@@ -128,7 +99,7 @@ module ActiveData
|
|
|
128
99
|
def generated_attributes_methods
|
|
129
100
|
@generated_attributes_methods ||=
|
|
130
101
|
const_set(:GeneratedAttributesMethods, Module.new)
|
|
131
|
-
|
|
102
|
+
.tap { |proxy| include proxy }
|
|
132
103
|
end
|
|
133
104
|
|
|
134
105
|
def inverted_attribute_aliases
|
|
@@ -139,37 +110,38 @@ module ActiveData
|
|
|
139
110
|
end
|
|
140
111
|
end
|
|
141
112
|
|
|
142
|
-
def initialize
|
|
113
|
+
def initialize(attrs = {})
|
|
143
114
|
assign_attributes attrs
|
|
144
115
|
end
|
|
145
116
|
|
|
146
|
-
def ==
|
|
117
|
+
def ==(other)
|
|
147
118
|
super || other.instance_of?(self.class) && other.attributes(false) == attributes(false)
|
|
148
119
|
end
|
|
149
120
|
alias_method :eql?, :==
|
|
150
121
|
|
|
151
122
|
def attribute(name)
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
123
|
+
reflection = self.class.reflect_on_attribute(name)
|
|
124
|
+
return unless reflection
|
|
125
|
+
initial_value = @initial_attributes.to_h.fetch(reflection.name, ActiveData::UNDEFINED)
|
|
126
|
+
@_attributes ||= {}
|
|
127
|
+
@_attributes[reflection.name] ||= reflection.build_attribute(self, initial_value)
|
|
156
128
|
end
|
|
157
129
|
|
|
158
|
-
def write_attribute
|
|
130
|
+
def write_attribute(name, value)
|
|
159
131
|
attribute(name).write(value)
|
|
160
132
|
end
|
|
161
133
|
alias_method :[]=, :write_attribute
|
|
162
134
|
|
|
163
|
-
def read_attribute
|
|
135
|
+
def read_attribute(name)
|
|
164
136
|
attribute(name).read
|
|
165
137
|
end
|
|
166
138
|
alias_method :[], :read_attribute
|
|
167
139
|
|
|
168
|
-
def read_attribute_before_type_cast
|
|
140
|
+
def read_attribute_before_type_cast(name)
|
|
169
141
|
attribute(name).read_before_type_cast
|
|
170
142
|
end
|
|
171
143
|
|
|
172
|
-
def attribute_present?
|
|
144
|
+
def attribute_present?(name)
|
|
173
145
|
attribute(name).value_present?
|
|
174
146
|
end
|
|
175
147
|
|
|
@@ -177,35 +149,22 @@ module ActiveData
|
|
|
177
149
|
Hash[attribute_names(include_associations).map { |name| [name, read_attribute(name)] }]
|
|
178
150
|
end
|
|
179
151
|
|
|
180
|
-
def update
|
|
152
|
+
def update(attrs)
|
|
181
153
|
assign_attributes(attrs)
|
|
182
154
|
end
|
|
183
155
|
alias_method :update_attributes, :update
|
|
184
156
|
|
|
185
|
-
def assign_attributes
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
attrs.stringify_keys!
|
|
190
|
-
represented_attrs = self.class.represented_names_and_aliases
|
|
191
|
-
.each_with_object({}) do |name, result|
|
|
192
|
-
result[name] = attrs.delete(name) if attrs.has_key?(name)
|
|
193
|
-
end
|
|
194
|
-
if self.class.is_a?(ActiveData::Model::Associations::NestedAttributes)
|
|
195
|
-
nested_attrs = self.class.nested_attributes_options.keys
|
|
196
|
-
.each_with_object({}) do |association_name, result|
|
|
197
|
-
name = "#{association_name}_attributes"
|
|
198
|
-
result[name] = attrs.delete(name) if attrs.has_key?(name)
|
|
199
|
-
end
|
|
200
|
-
end
|
|
157
|
+
def assign_attributes(attrs)
|
|
158
|
+
attrs.each do |name, value|
|
|
159
|
+
name = name.to_s
|
|
160
|
+
sanitize_value = self.class._sanitize && name == self.class.primary_name
|
|
201
161
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
162
|
+
if respond_to?("#{name}=") && !sanitize_value
|
|
163
|
+
public_send("#{name}=", value)
|
|
164
|
+
else
|
|
165
|
+
logger.info("Ignoring #{sanitize_value ? 'primary' : 'undefined'} `#{name}` attribute value for #{self} during mass-assignment")
|
|
166
|
+
end
|
|
207
167
|
end
|
|
208
|
-
true
|
|
209
168
|
end
|
|
210
169
|
alias_method :attributes=, :assign_attributes
|
|
211
170
|
|
|
@@ -213,7 +172,7 @@ module ActiveData
|
|
|
213
172
|
"#<#{self.class.send(:original_inspect)} #{attributes_for_inspect.presence || '(no attributes)'}>"
|
|
214
173
|
end
|
|
215
174
|
|
|
216
|
-
def initialize_copy
|
|
175
|
+
def initialize_copy(_)
|
|
217
176
|
@initial_attributes = Hash[attribute_names.map do |name|
|
|
218
177
|
[name, read_attribute_before_type_cast(name)]
|
|
219
178
|
end]
|
|
@@ -223,22 +182,9 @@ module ActiveData
|
|
|
223
182
|
|
|
224
183
|
private
|
|
225
184
|
|
|
226
|
-
def _assign_attributes attrs
|
|
227
|
-
attrs.each do |name, value|
|
|
228
|
-
name = name.to_s
|
|
229
|
-
sanitize_value = self.class._sanitize && name == self.class.primary_name
|
|
230
|
-
|
|
231
|
-
if respond_to?("#{name}=") && !sanitize_value
|
|
232
|
-
public_send("#{name}=", value)
|
|
233
|
-
else
|
|
234
|
-
logger.info("Ignoring #{sanitize_value ? 'primary' : 'undefined'} `#{name}` attribute value for #{self} during mass-assignment")
|
|
235
|
-
end
|
|
236
|
-
end
|
|
237
|
-
end
|
|
238
|
-
|
|
239
185
|
def attributes_for_inspect
|
|
240
186
|
attribute_names(false).map do |name|
|
|
241
|
-
prefix = self.class.primary_name == name ?
|
|
187
|
+
prefix = self.class.primary_name == name ? '*' : ''
|
|
242
188
|
"#{prefix}#{attribute(name).inspect_attribute}"
|
|
243
189
|
end.join(', ')
|
|
244
190
|
end
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
module ActiveData
|
|
2
2
|
module Model
|
|
3
|
-
|
|
4
3
|
# == Callbacks for ActiveData::Model lifecycle
|
|
5
4
|
#
|
|
6
5
|
# Provides ActiveModel callbacks support for lifecycle
|
|
@@ -45,24 +44,24 @@ module ActiveData
|
|
|
45
44
|
end
|
|
46
45
|
|
|
47
46
|
module PrependMethods
|
|
48
|
-
def initialize
|
|
49
|
-
super
|
|
47
|
+
def initialize(*_)
|
|
48
|
+
super
|
|
50
49
|
run_callbacks :initialize
|
|
51
50
|
end
|
|
52
51
|
|
|
53
|
-
def save_object
|
|
52
|
+
def save_object(&block)
|
|
54
53
|
run_callbacks(:save) { super(&block) }
|
|
55
54
|
end
|
|
56
55
|
|
|
57
|
-
def create_object
|
|
56
|
+
def create_object(&block)
|
|
58
57
|
run_callbacks(:create) { super(&block) }
|
|
59
58
|
end
|
|
60
59
|
|
|
61
|
-
def update_object
|
|
60
|
+
def update_object(&block)
|
|
62
61
|
run_callbacks(:update) { super(&block) }
|
|
63
62
|
end
|
|
64
63
|
|
|
65
|
-
def destroy_object
|
|
64
|
+
def destroy_object(&block)
|
|
66
65
|
run_callbacks(:destroy) { super(&block) }
|
|
67
66
|
end
|
|
68
67
|
end
|
|
@@ -12,8 +12,8 @@ module ActiveData
|
|
|
12
12
|
def self.append_features(base)
|
|
13
13
|
unconcerned_append_features(base)
|
|
14
14
|
end
|
|
15
|
-
|
|
16
|
-
end
|
|
15
|
+
|
|
16
|
+
def self.included(_base); end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
included do
|
|
@@ -42,13 +42,13 @@ module ActiveData
|
|
|
42
42
|
attribute_names(false).each do |name|
|
|
43
43
|
define_dirty name, generated_attributes_methods
|
|
44
44
|
end
|
|
45
|
-
_attribute_aliases.
|
|
45
|
+
_attribute_aliases.each_key do |name|
|
|
46
46
|
define_dirty name, generated_attributes_methods
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
module ClassMethods
|
|
51
|
-
def define_dirty
|
|
51
|
+
def define_dirty(method, target = self)
|
|
52
52
|
reflection = reflect_on_attribute(method)
|
|
53
53
|
name = reflection ? reflection.name : method
|
|
54
54
|
|