store_attribute 1.1.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6078ba7214bee86726edd35c8cfbac054907c2aada0e5644d63b906b1884cb37
4
- data.tar.gz: b3ac4c23dfdc1f8412fccf67fe8c7e9a441943ae7d3adba95eb735e7cd5e0302
3
+ metadata.gz: 6c4bd7ca51c3191e560a7cfb18a9edde7caa40c571992a26a84352da9ee5d5d0
4
+ data.tar.gz: 2577ac2836e7c11b7857b5c8b98b8c3e208480b226e1ec2813ade8377324a97f
5
5
  SHA512:
6
- metadata.gz: 2c8b70decca97c29ec6b112265d318f7fcb598a87dccbcc6531fc7f9e1de8701830f7d963f6890cfb453704ad19b14e2b6550d9d513c33fbfadf85952a9491a4
7
- data.tar.gz: 41a9e77501f4c9e4df33a06fa343c0377e8cb982b0dfda250003345e16d4afc635b39b99c9570ded1f7af27a6781b76c8dba013b3586bf699c048260159bf507
6
+ metadata.gz: 6f8bcb86379b5235cde3e19b96dbbba05ec2908b409882d872fb86913f2adfc9943f6a54bc0d20f5a8b5fd1c0373edc31594bc999d07c7f229954b13d5287567
7
+ data.tar.gz: cefb661c7a3e7f7add6a1ffac5eafcbae3941db2a4cc74a8e5fc5b827f10721c409ea8434730c8e6a0ba6cd706daa7e7b1276b7a52efe15bc6709e6047f6e055
data/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 1.3.0 (2024-09-03) 🗓️
6
+
7
+ - Fix using defaults when store attributes are inherited from a parent model. ([@palkan][])
8
+
9
+ - Allow specifying only default values w/o types. ([@palkan][])
10
+
11
+ ```ruby
12
+ store_attribute :store, :tags, default: []
13
+ ```
14
+
15
+ - **Ruby >= 2.7 and Rails >= 6.1 are required**. ([@palkan][])
16
+
17
+ ## 1.2.0 (2023-11-29)
18
+
19
+ - Support Rails >7.1. ([@palkan][])
20
+
21
+ - Fix handling of store attributes for not-yet-defined columns. ([@palkan][])
22
+
5
23
  ## 1.1.1 (2023-06-27)
6
24
 
7
25
  - Lookup store attribute types only after schema load.
data/README.md CHANGED
@@ -13,7 +13,7 @@ Originally extracted from not merged PR to Rails: [rails/rails#18942](https://gi
13
13
  In your Gemfile:
14
14
 
15
15
  ```ruby
16
- # for Rails 6+ (7 is supported)
16
+ # for Rails 6.1+ (7 is supported)
17
17
  gem "store_attribute", "~> 1.0"
18
18
 
19
19
  # for Rails 5+ (6 is supported)
@@ -30,6 +30,7 @@ module ActiveRecord
30
30
  # end
31
31
  def store(store_name, options = {})
32
32
  accessors = options.delete(:accessors)
33
+ accessor_related_options = options.slice(:prefix, :suffix)
33
34
  typed_accessors =
34
35
  if accessors && accessors.last.is_a?(Hash)
35
36
  accessors.pop
@@ -38,7 +39,7 @@ module ActiveRecord
38
39
  end
39
40
 
40
41
  _orig_store_without_types(store_name, options)
41
- store_accessor(store_name, *accessors, **typed_accessors) if accessors
42
+ store_accessor(store_name, *accessors, **accessor_related_options, **typed_accessors) if accessors
42
43
  end
43
44
 
44
45
  # Adds additional accessors to an existing store on this model.
@@ -114,17 +115,24 @@ module ActiveRecord
114
115
  # u.ratio # => "3.141592653"
115
116
  #
116
117
  # # On the other hand, writing through accessor set correct data within store
117
- # u.ratio = "3.14.1592653"
118
+ # u.ratio = "3.141592653"
118
119
  # u.ratio # => 3
119
120
  # u.settings['ratio'] # => 3
120
121
  #
121
122
  # For more examples on using types, see documentation for ActiveRecord::Attributes.
122
- def store_attribute(store_name, name, type, prefix: nil, suffix: nil, **options)
123
+ def store_attribute(store_name, name, type = :value, prefix: nil, suffix: nil, **options)
123
124
  _orig_store_accessor_without_types(store_name, name.to_s, prefix: prefix, suffix: suffix)
124
125
  _define_predicate_method(name, prefix: prefix, suffix: suffix) if type == :boolean
125
126
 
126
- _define_store_attribute(store_name) if !_local_typed_stored_attributes? || _local_typed_stored_attributes[store_name].empty?
127
- _local_typed_stored_attributes[store_name][name] = [type, options]
127
+ _define_store_attribute(store_name) if !_local_typed_stored_attributes? ||
128
+ _local_typed_stored_attributes[store_name][:types].empty? ||
129
+ # Defaults owner has changed, we must decorate the attribute to correctly propagate the defaults
130
+ (
131
+ options.key?(:default) && _local_typed_stored_attributes[store_name][:owner] != self
132
+ )
133
+
134
+ _local_typed_stored_attributes[store_name][:owner] = self if options.key?(:default) || !_local_typed_stored_attributes?
135
+ _local_typed_stored_attributes[store_name][:types][name] = [type, options]
128
136
  end
129
137
 
130
138
  def store_attribute_unset_values_fallback_to_default
@@ -148,27 +156,24 @@ module ActiveRecord
148
156
  @local_typed_stored_attributes =
149
157
  if superclass.respond_to?(:_local_typed_stored_attributes)
150
158
  superclass._local_typed_stored_attributes.dup.tap do |h|
151
- h.transform_values!(&:dup)
159
+ h.transform_values! { |v| {owner: v[:owner], types: v[:types].dup} }
152
160
  end
153
161
  else
154
- Hash.new { |h, k| h[k] = {}.with_indifferent_access }.with_indifferent_access
162
+ Hash.new { |h, k| h[k] = {types: {}.with_indifferent_access} }.with_indifferent_access
155
163
  end
156
164
  end
157
165
 
158
166
  def _define_store_attribute(store_name)
159
167
  attr_name = store_name.to_s
160
- was_type = attributes_to_define_after_schema_loads[attr_name]&.first
161
-
162
- # For Rails <6.1
163
- use_decorator = respond_to?(:decorate_attribute_type) && method(:decorate_attribute_type).parameters.count { |type, _| type == :req } == 2
164
168
 
165
169
  defaultik = Type::TypedStore::Defaultik.new
166
170
 
167
171
  owner = self
168
172
 
169
- if use_decorator
173
+ # For Rails <6.1
174
+ if respond_to?(:decorate_attribute_type) && method(:decorate_attribute_type).parameters.count { |type, _| type == :req } == 2
170
175
  decorate_attribute_type(attr_name, "typed_accessor_for_#{attr_name}") do |subtype|
171
- subtypes = _local_typed_stored_attributes[attr_name]
176
+ subtypes = _local_typed_stored_attributes[attr_name][:types]
172
177
  type = Type::TypedStore.create_from_type(subtype)
173
178
  type.owner = owner
174
179
  defaultik.type = type
@@ -180,9 +185,27 @@ module ActiveRecord
180
185
 
181
186
  type
182
187
  end
188
+ # Rails >7.1
189
+ elsif respond_to?(:decorate_attributes)
190
+ decorate_attributes([attr_name]) do |_, subtype|
191
+ subtypes = _local_typed_stored_attributes[attr_name][:types]
192
+ type = Type::TypedStore.create_from_type(subtype)
193
+ type.owner = owner
194
+ defaultik.type = type
195
+ subtypes.each do |name, (cast_type, options)|
196
+ type.add_typed_key(name, cast_type, **options.symbolize_keys)
197
+ end
198
+
199
+ type
200
+ end
201
+
202
+ attribute(attr_name, default: defaultik.proc)
203
+ # Rails >=6.1, <=7.1
183
204
  else
205
+ was_type = attributes_to_define_after_schema_loads[attr_name]&.first
206
+
184
207
  attribute(attr_name, default: defaultik.proc) do |subtype|
185
- subtypes = _local_typed_stored_attributes[attr_name]
208
+ subtypes = _local_typed_stored_attributes[attr_name][:types]
186
209
  subtype = _lookup_cast_type(attr_name, was_type, {}) if defined?(_lookup_cast_type)
187
210
 
188
211
  type = Type::TypedStore.create_from_type(subtype)
@@ -30,13 +30,14 @@ module ActiveRecord
30
30
  def initialize(subtype)
31
31
  @accessor_types = {}
32
32
  @defaults = {}
33
- @store_accessor = subtype.accessor
34
- super(subtype)
33
+ @subtype = subtype
34
+ super
35
35
  end
36
36
 
37
37
  UNDEFINED = Object.new
38
38
 
39
39
  def add_typed_key(key, type, default: UNDEFINED, **options)
40
+ type = ActiveModel::Type::Value.new(**options) if type == :value
40
41
  type = ActiveRecord::Type.lookup(type, **options) if type.is_a?(Symbol)
41
42
  safe_key = key.to_s
42
43
  @accessor_types[safe_key] = type
@@ -61,7 +62,7 @@ module ActiveRecord
61
62
  end
62
63
 
63
64
  def serialize(value)
64
- return super(value) unless value.is_a?(Hash)
65
+ return super unless value.is_a?(Hash)
65
66
  typed_casted = {}
66
67
  accessor_types.each do |str_key, type|
67
68
  key = key_to_cast(value, str_key)
@@ -118,7 +119,7 @@ module ActiveRecord
118
119
  def key_to_cast(val, key)
119
120
  return key if val.key?(key)
120
121
  return key.to_sym if val.key?(key.to_sym)
121
- return key if defaults.key?(key)
122
+ key if defaults.key?(key)
122
123
  end
123
124
 
124
125
  def typed?(key)
@@ -133,7 +134,11 @@ module ActiveRecord
133
134
  owner&.store_attribute_unset_values_fallback_to_default && defaults.key?(key)
134
135
  end
135
136
 
136
- attr_reader :accessor_types, :defaults, :store_accessor, :owner
137
+ def store_accessor
138
+ subtype.accessor
139
+ end
140
+
141
+ attr_reader :accessor_types, :defaults, :subtype, :owner
137
142
  end
138
143
  end
139
144
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StoreAttribute # :nodoc:
4
- VERSION = "1.1.1"
4
+ VERSION = "1.3.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: store_attribute
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - palkan
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-27 00:00:00.000000000 Z
11
+ date: 2024-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '6.0'
19
+ version: '6.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '6.0'
26
+ version: '6.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pg
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0.18'
33
+ version: '1.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0.18'
40
+ version: '1.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -91,7 +91,7 @@ metadata:
91
91
  documentation_uri: http://github.com/palkan/store_attribute
92
92
  homepage_uri: http://github.com/palkan/store_attribute
93
93
  source_code_uri: http://github.com/palkan/store_attribute
94
- post_install_message:
94
+ post_install_message:
95
95
  rdoc_options: []
96
96
  require_paths:
97
97
  - lib
@@ -99,15 +99,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - ">="
101
101
  - !ruby/object:Gem::Version
102
- version: 2.6.0
102
+ version: 2.7.0
103
103
  required_rubygems_version: !ruby/object:Gem::Requirement
104
104
  requirements:
105
105
  - - ">="
106
106
  - !ruby/object:Gem::Version
107
107
  version: '0'
108
108
  requirements: []
109
- rubygems_version: 3.4.8
110
- signing_key:
109
+ rubygems_version: 3.4.19
110
+ signing_key:
111
111
  specification_version: 4
112
112
  summary: ActiveRecord extension which adds typecasting to store accessors
113
113
  test_files: []