duck_record 0.0.7 → 0.0.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 06bf2457884cf16768ed22c8eab54c06cd03e59d
4
- data.tar.gz: 2b9fdb3b1e20e91e52e2e553f061302f777d2885
3
+ metadata.gz: 26cdafb4677192d3b19b66b6c691f739e6dc70ae
4
+ data.tar.gz: 5c1e47c06bece7781a4812389dbc7218ae240ed1
5
5
  SHA512:
6
- metadata.gz: 42bfba1df7380612fa22a300225f8e75e46e14bccc565c7c1e403105d7b6bba293376e32e08a6a74fd7c47a21120c5a86ef836eabde8a23bac818eb7b80817b1
7
- data.tar.gz: '095d81f5ac4b851f3989f6bba870e0dd30cbf2c4542968183dc4e963fcc6a2162deb0956519ff9b9f1205acad6baa5fcb61f9de42db9de4f23d9935ead1ac449'
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::AttributeAssignment
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
- assign_nested_parameter_attributes(nested_parameter_attributes) unless nested_parameter_attributes.empty?
29
- assign_multiparameter_attributes(multi_parameter_attributes) unless multi_parameter_attributes.empty?
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
- self.class.attribute_alias(attr_name).to_s
34
- else
35
- attr_name.to_s
36
- end
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
@@ -276,6 +276,7 @@ module DuckRecord #:nodoc:
276
276
  extend Translation
277
277
 
278
278
  include Core
279
+ include ReadonlyAttributes
279
280
  include ModelSchema
280
281
  include Inheritance
281
282
  include AttributeAssignment
@@ -66,7 +66,7 @@ module DuckRecord
66
66
  initialize_internals_callback
67
67
 
68
68
  if attributes
69
- assign_attributes(attributes)
69
+ assign_attributes(attributes, force_write_readonly: true)
70
70
  clear_changes_information
71
71
  end
72
72
 
@@ -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
@@ -1,3 +1,3 @@
1
1
  module DuckRecord
2
- VERSION = '0.0.7'
2
+ VERSION = '0.0.8'
3
3
  end
data/lib/duck_record.rb CHANGED
@@ -15,6 +15,7 @@ module DuckRecord
15
15
  autoload :Inheritance
16
16
  autoload :ModelSchema
17
17
  autoload :NestedAttributes
18
+ autoload :ReadonlyAttributes
18
19
  autoload :Reflection
19
20
  autoload :Serialization
20
21
  autoload :Translation
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.7
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-17 00:00:00.000000000 Z
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