duck_record 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/duck_record/attribute_assignment.rb +41 -13
- data/lib/duck_record/attribute_methods/write.rb +15 -13
- data/lib/duck_record/base.rb +1 -0
- data/lib/duck_record/core.rb +1 -1
- data/lib/duck_record/readonly_attributes.rb +23 -0
- data/lib/duck_record/version.rb +1 -1
- data/lib/duck_record.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 26cdafb4677192d3b19b66b6c691f739e6dc70ae
|
4
|
+
data.tar.gz: 5c1e47c06bece7781a4812389dbc7218ae240ed1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddf042c24da96f908e7dcb8183566574a7208e02da658e8cf023a8e729e63019a9a659c66a7f782ed8055842f7b45ac5fa74a690bd3d91b2e6901e428a474ee6
|
7
|
+
data.tar.gz: 6a63e7f449a1815fc742fc93530f90407645bb6d1b51ff5382dc4b6102e4dacd4eeb113b82a49c8125e972289a5ab8c856680dc0ceeabe9db927458c8e47a6ba
|
@@ -1,18 +1,29 @@
|
|
1
|
+
require 'active_support/core_ext/hash/keys'
|
1
2
|
require 'active_model/forbidden_attributes_protection'
|
2
3
|
|
3
4
|
module DuckRecord
|
4
5
|
module AttributeAssignment
|
5
6
|
extend ActiveSupport::Concern
|
6
|
-
include ActiveModel::
|
7
|
+
include ActiveModel::ForbiddenAttributesProtection
|
7
8
|
|
8
9
|
# Alias for ActiveModel::AttributeAssignment#assign_attributes. See ActiveModel::AttributeAssignment.
|
9
|
-
def attributes=(attributes)
|
10
|
-
assign_attributes(attributes)
|
10
|
+
def attributes=(attributes, force_write_readonly: false)
|
11
|
+
assign_attributes(attributes, force_write_readonly: force_write_readonly)
|
12
|
+
end
|
13
|
+
|
14
|
+
def assign_attributes(new_attributes, force_write_readonly: false)
|
15
|
+
unless new_attributes.respond_to?(:stringify_keys)
|
16
|
+
raise ArgumentError, "When assigning attributes, you must pass a hash as an argument."
|
17
|
+
end
|
18
|
+
return if new_attributes.nil? || new_attributes.empty?
|
19
|
+
|
20
|
+
attributes = new_attributes.stringify_keys
|
21
|
+
_assign_attributes(sanitize_for_mass_assignment(attributes), force_write_readonly: force_write_readonly)
|
11
22
|
end
|
12
23
|
|
13
24
|
private
|
14
25
|
|
15
|
-
def _assign_attributes(attributes)
|
26
|
+
def _assign_attributes(attributes, force_write_readonly: false)
|
16
27
|
multi_parameter_attributes = {}
|
17
28
|
nested_parameter_attributes = {}
|
18
29
|
|
@@ -23,15 +34,23 @@ module DuckRecord
|
|
23
34
|
nested_parameter_attributes[k] = attributes.delete(k)
|
24
35
|
end
|
25
36
|
end
|
26
|
-
super(attributes)
|
27
37
|
|
28
|
-
|
29
|
-
|
38
|
+
attributes.each do |k, v|
|
39
|
+
_assign_attribute(k, v, force_write_readonly: force_write_readonly)
|
40
|
+
end
|
41
|
+
|
42
|
+
unless nested_parameter_attributes.empty?
|
43
|
+
assign_nested_parameter_attributes(nested_parameter_attributes, force_write_readonly: force_write_readonly)
|
44
|
+
end
|
45
|
+
|
46
|
+
unless multi_parameter_attributes.empty?
|
47
|
+
assign_multiparameter_attributes(multi_parameter_attributes, force_write_readonly: force_write_readonly)
|
48
|
+
end
|
30
49
|
end
|
31
50
|
|
32
51
|
# Assign any deferred nested attributes after the base attributes have been set.
|
33
|
-
def assign_nested_parameter_attributes(pairs)
|
34
|
-
pairs.each { |k, v| _assign_attribute(k, v) }
|
52
|
+
def assign_nested_parameter_attributes(pairs, force_write_readonly: false)
|
53
|
+
pairs.each { |k, v| _assign_attribute(k, v, force_write_readonly: force_write_readonly) }
|
35
54
|
end
|
36
55
|
|
37
56
|
# Instantiates objects for all attribute classes that needs more than one constructor parameter. This is done
|
@@ -40,13 +59,14 @@ module DuckRecord
|
|
40
59
|
# written_on (a date type) with Date.new("2004", "6", "24"). You can also specify a typecast character in the
|
41
60
|
# parentheses to have the parameters typecasted before they're used in the constructor. Use i for Integer and
|
42
61
|
# f for Float. If all the values for a given attribute are empty, the attribute will be set to +nil+.
|
43
|
-
def assign_multiparameter_attributes(pairs)
|
62
|
+
def assign_multiparameter_attributes(pairs, force_write_readonly: false)
|
44
63
|
execute_callstack_for_multiparameter_attributes(
|
45
|
-
extract_callstack_for_multiparameter_attributes(pairs)
|
64
|
+
extract_callstack_for_multiparameter_attributes(pairs),
|
65
|
+
force_write_readonly: force_write_readonly
|
46
66
|
)
|
47
67
|
end
|
48
68
|
|
49
|
-
def execute_callstack_for_multiparameter_attributes(callstack)
|
69
|
+
def execute_callstack_for_multiparameter_attributes(callstack, force_write_readonly: false)
|
50
70
|
errors = []
|
51
71
|
callstack.each do |name, values_with_empty_parameters|
|
52
72
|
begin
|
@@ -55,7 +75,7 @@ module DuckRecord
|
|
55
75
|
else
|
56
76
|
values = values_with_empty_parameters
|
57
77
|
end
|
58
|
-
send("#{name}=", values)
|
78
|
+
send("#{name}=", values, force_write_readonly: force_write_readonly)
|
59
79
|
rescue => ex
|
60
80
|
errors << AttributeAssignmentError.new("error on assignment #{values_with_empty_parameters.values.inspect} to #{name} (#{ex.message})", ex, name)
|
61
81
|
end
|
@@ -87,5 +107,13 @@ module DuckRecord
|
|
87
107
|
def find_parameter_position(multiparameter_name)
|
88
108
|
multiparameter_name.scan(/\(([0-9]*).*\)/).first.first.to_i
|
89
109
|
end
|
110
|
+
|
111
|
+
def _assign_attribute(k, v, force_write_readonly: false)
|
112
|
+
if respond_to?("#{k}=")
|
113
|
+
public_send("#{k}=", v, force_write_readonly: force_write_readonly)
|
114
|
+
else
|
115
|
+
raise UnknownAttributeError.new(self, k)
|
116
|
+
end
|
117
|
+
end
|
90
118
|
end
|
91
119
|
end
|
@@ -15,9 +15,9 @@ module DuckRecord
|
|
15
15
|
DuckRecord::AttributeMethods::AttrNames.set_name_cache safe_name, name
|
16
16
|
|
17
17
|
generated_attribute_methods.module_eval <<-STR, __FILE__, __LINE__ + 1
|
18
|
-
def __temp__#{safe_name}=(value)
|
18
|
+
def __temp__#{safe_name}=(value, force_write_readonly: false)
|
19
19
|
name = ::DuckRecord::AttributeMethods::AttrNames::ATTR_#{safe_name}
|
20
|
-
write_attribute(name, value)
|
20
|
+
write_attribute(name, value, force_write_readonly: force_write_readonly)
|
21
21
|
end
|
22
22
|
alias_method #{(name + '=').inspect}, :__temp__#{safe_name}=
|
23
23
|
undef_method :__temp__#{safe_name}=
|
@@ -28,30 +28,32 @@ module DuckRecord
|
|
28
28
|
# Updates the attribute identified by <tt>attr_name</tt> with the
|
29
29
|
# specified +value+. Empty strings for Integer and Float columns are
|
30
30
|
# turned into +nil+.
|
31
|
-
def write_attribute(attr_name, value)
|
31
|
+
def write_attribute(attr_name, value, force_write_readonly: false)
|
32
32
|
name = if self.class.attribute_alias?(attr_name)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
self.class.attribute_alias(attr_name).to_s
|
34
|
+
else
|
35
|
+
attr_name.to_s
|
36
|
+
end
|
37
37
|
|
38
|
-
write_attribute_with_type_cast(name, value, true)
|
38
|
+
write_attribute_with_type_cast(name, value, true, force_write_readonly: force_write_readonly)
|
39
39
|
end
|
40
40
|
|
41
|
-
def raw_write_attribute(attr_name, value) # :nodoc:
|
42
|
-
write_attribute_with_type_cast(attr_name, value, false)
|
41
|
+
def raw_write_attribute(attr_name, value, force_write_readonly: false) # :nodoc:
|
42
|
+
write_attribute_with_type_cast(attr_name, value, false, force_write_readonly: force_write_readonly)
|
43
43
|
end
|
44
44
|
|
45
45
|
private
|
46
46
|
|
47
47
|
# Handle *= for method_missing.
|
48
|
-
def attribute=(attribute_name, value)
|
49
|
-
write_attribute(attribute_name, value)
|
48
|
+
def attribute=(attribute_name, value, force_write_readonly: false)
|
49
|
+
write_attribute(attribute_name, value, force_write_readonly: force_write_readonly)
|
50
50
|
end
|
51
51
|
|
52
|
-
def write_attribute_with_type_cast(attr_name, value, should_type_cast)
|
52
|
+
def write_attribute_with_type_cast(attr_name, value, should_type_cast, force_write_readonly: false)
|
53
53
|
attr_name = attr_name.to_s
|
54
54
|
|
55
|
+
return if !force_write_readonly && self.class.readonly_attributes.include?(attr_name)
|
56
|
+
|
55
57
|
if should_type_cast
|
56
58
|
@attributes.write_from_user(attr_name, value)
|
57
59
|
else
|
data/lib/duck_record/base.rb
CHANGED
data/lib/duck_record/core.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
module DuckRecord
|
2
|
+
module ReadonlyAttributes
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :_attr_readonly, instance_accessor: false
|
7
|
+
self._attr_readonly = []
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
# Attributes listed as readonly will be used to create a new record but update operations will
|
12
|
+
# ignore these fields.
|
13
|
+
def attr_readonly(*attributes)
|
14
|
+
self._attr_readonly = Set.new(attributes.map(&:to_s)) + (_attr_readonly || [])
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns an array of all the attributes that have been specified as readonly.
|
18
|
+
def readonly_attributes
|
19
|
+
_attr_readonly
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/duck_record/version.rb
CHANGED
data/lib/duck_record.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duck_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jasl
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-03-
|
11
|
+
date: 2017-03-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -100,6 +100,7 @@ files:
|
|
100
100
|
- lib/duck_record/model_schema.rb
|
101
101
|
- lib/duck_record/nested_attributes.rb
|
102
102
|
- lib/duck_record/nested_validate_association.rb
|
103
|
+
- lib/duck_record/readonly_attributes.rb
|
103
104
|
- lib/duck_record/reflection.rb
|
104
105
|
- lib/duck_record/serialization.rb
|
105
106
|
- lib/duck_record/translation.rb
|