store_model 2.1.0 → 2.1.2

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
  SHA256:
3
- metadata.gz: 61353c039b8274db76c67d73081ce718a5446e392df4bd5987f4dde023d5b244
4
- data.tar.gz: 40f5011957af3787650b1f3565468fc0b59a4c1a2e090735e8cbf9926e8b622e
3
+ metadata.gz: db36f4fa51b9f71a34198ba18b921565d46a450c62e4892628dfee8e067bf4ff
4
+ data.tar.gz: 4e72e8f0fc7051105a09843040a4cfc61f248884ac2dcc8def0f6a95f9b8390f
5
5
  SHA512:
6
- metadata.gz: 5e3065c9503681ac881fe2e2b2194bfc9f9c959c66e4a6430b47160ff4487cc1bdc6f4408dfc72e216f94eae729ce8462e09ae12364e3e37ef5341769588a796
7
- data.tar.gz: 427cb2dab39fd79ef74fb3b1a1e48f89003fbb2e00ca25488cea257cc9f87c9aad5eedb4c469252a605e5932420ad6e257898e85ab7622c904c7cec99c75af73
6
+ metadata.gz: 5c5073d90550cd90049cb0cc2555bfab36c4b036857319ac5bf0f0eeadaea70deabcf71e549c7e1348127f719ba9f03bda444fb700153b8bdbbb5ffdc3e36c0f
7
+ data.tar.gz: f5a3eed707850087dfc95c908725624352da067410b3fa69762764545fd83c243a99bfbf8a4b4ae53086fdff9094377769be720cf7497b0d82ae1d7ad736e411
@@ -7,7 +7,7 @@ require "store_model/nested_attributes"
7
7
 
8
8
  module StoreModel
9
9
  # When included into class configures it to handle JSON column
10
- module Model
10
+ module Model # rubocop:disable Metrics/ModuleLength
11
11
  def self.included(base) # :nodoc:
12
12
  base.include ActiveModel::Model
13
13
  base.include ActiveModel::Attributes
@@ -44,7 +44,10 @@ module StoreModel
44
44
  StoreModel.config.serialize_enums_using_as_json
45
45
  end
46
46
 
47
- result = attributes.with_indifferent_access
47
+ result = @attributes.keys.each_with_object({}) do |key, values|
48
+ values[key] = serialized_attribute(key)
49
+ end.with_indifferent_access
50
+
48
51
  result.merge!(unknown_attributes) if serialize_unknown_attributes
49
52
  result.as_json(options).tap do |json|
50
53
  serialize_enums!(json) if serialize_enums_using_as_json
@@ -175,17 +178,6 @@ module StoreModel
175
178
  @unknown_attributes ||= {}
176
179
  end
177
180
 
178
- # Serialized values for storing in db
179
- #
180
- # @return [Hash]
181
- def values_for_database
182
- result = @attributes.keys.each_with_object({}) do |key, values|
183
- values[key] = @attributes.fetch(key).value_for_database
184
- end
185
- result.merge!(unknown_attributes)
186
- result
187
- end
188
-
189
181
  private
190
182
 
191
183
  def attribute?(attribute)
@@ -207,5 +199,16 @@ module StoreModel
207
199
  json[name] = public_send(name).as_json unless json[name].nil?
208
200
  end
209
201
  end
202
+
203
+ def serialized_attribute(attr_name)
204
+ attr = @attributes.fetch(attr_name)
205
+ if attr.value.is_a? StoreModel::Model
206
+ Types::RawJSONEncoder.new(attr.value_for_database)
207
+ elsif attr.value.is_a? Array
208
+ attr.value.as_json
209
+ else
210
+ attr.value_for_database
211
+ end
212
+ end
210
213
  end
211
214
  end
@@ -35,25 +35,45 @@ module StoreModel
35
35
  #
36
36
  # See https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#method-i-accepts_nested_attributes_for
37
37
  def accepts_nested_attributes_for(*attributes)
38
- global_options = attributes.extract_options!
38
+ options = attributes.extract_options!
39
39
 
40
- attributes.each do |attribute, options|
41
- case attribute_types[attribute.to_s]
40
+ attributes.each do |attribute|
41
+ case nested_attribute_type(attribute)
42
42
  when Types::OneBase, Types::ManyBase
43
- define_store_model_attr_accessors(attribute, options || global_options)
43
+ options.reverse_merge!(allow_destroy: false, update_only: false)
44
+ define_store_model_attr_accessors(attribute, options)
44
45
  else
45
- super(attribute, options || global_options)
46
+ super(*attribute, options)
46
47
  end
47
48
  end
48
49
  end
49
50
 
50
51
  private
51
52
 
53
+ # If attribute defined in ActiveRecord model but you dont yet have database created
54
+ # you cannot access attribute types.
55
+ # To handle this case, we can use ActiveRecord::Attributes 'attributes_to_define_after_schema_loads'
56
+ # which stores information about custom defined attributes.
57
+ # See ActiveRecord::Attributes#atribute
58
+ # If #accepts_nested_attributes_for is used inside active model instance
59
+ # schema is not required to determine attribute type so we can still use attribute_types
60
+ # If schema loaded the attribute_types already populated and we can safely use it
61
+ # See ActiveRecord::ModelSchema#load_schema!
62
+ def nested_attribute_type(attribute)
63
+ if self < ActiveRecord::Base && !schema_loaded?
64
+ attributes_to_define_after_schema_loads[attribute.to_s]&.first
65
+ else
66
+ attribute_types[attribute.to_s]
67
+ end
68
+ end
69
+
52
70
  def define_store_model_attr_accessors(attribute, options)
53
- case attribute_types[attribute.to_s]
71
+ case nested_attribute_type(attribute)
54
72
  when Types::OneBase
55
73
  define_association_setter_for_single(attribute, options)
56
- alias_method "#{attribute}_attributes=", "#{attribute}="
74
+ define_method "#{attribute}_attributes=" do |*args, **kwargs|
75
+ send("#{attribute}=", *args, **kwargs)
76
+ end
57
77
  when Types::ManyBase
58
78
  define_association_setter_for_many(attribute, options)
59
79
  end
@@ -88,7 +108,10 @@ module StoreModel
88
108
  end
89
109
  end
90
110
 
91
- def assign_nested_attributes_for_collection_association(association, attributes, options)
111
+ # Base
112
+ def assign_nested_attributes_for_collection_association(association, attributes, options = nil)
113
+ return super(association, attributes) unless options
114
+
92
115
  attributes = attributes.values if attributes.is_a?(Hash)
93
116
 
94
117
  if options&.dig(:allow_destroy)
@@ -46,9 +46,7 @@ module StoreModel
46
46
  # @return [String] serialized value
47
47
  def serialize(value)
48
48
  case value
49
- when @model_klass
50
- ActiveSupport::JSON.encode(value.values_for_database)
51
- when Hash
49
+ when @model_klass, Hash
52
50
  ActiveSupport::JSON.encode(value)
53
51
  else
54
52
  super
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StoreModel
4
+ module Types
5
+ # Implements #encode_json and #as_json methods.
6
+ # By wrapping serialized objects in this type, it prevents duplicate
7
+ # JSON serialization passes on nested object. It is named as Encoder
8
+ # as it will not work to inflate typed attributes and is intended
9
+ # to be used internally.
10
+ class RawJSONEncoder < String
11
+ def encode_json(_encoder)
12
+ self
13
+ end
14
+
15
+ def as_json(_options = nil)
16
+ JSON.parse(self)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -14,6 +14,8 @@ require "store_model/types/enum_type"
14
14
 
15
15
  require "store_model/types/one_of"
16
16
 
17
+ require "store_model/types/raw_json"
18
+
17
19
  module StoreModel
18
20
  # Contains all custom types.
19
21
  module Types
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StoreModel # :nodoc:
4
- VERSION = "2.1.0"
4
+ VERSION = "2.1.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: store_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - DmitryTsepelev
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-31 00:00:00.000000000 Z
11
+ date: 2023-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -115,6 +115,7 @@ files:
115
115
  - lib/store_model/types/one_of.rb
116
116
  - lib/store_model/types/one_polymorphic.rb
117
117
  - lib/store_model/types/polymorphic_helper.rb
118
+ - lib/store_model/types/raw_json.rb
118
119
  - lib/store_model/version.rb
119
120
  homepage: https://github.com/DmitryTsepelev/store_model
120
121
  licenses: