store_attribute 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/LICENSE.txt +1 -1
- data/README.md +19 -6
- data/lib/store_attribute/active_record/mutation_tracker.rb +1 -0
- data/lib/store_attribute/active_record/store.rb +18 -1
- data/lib/store_attribute/active_record/type/typed_store.rb +13 -1
- data/lib/store_attribute/version.rb +1 -1
- data/lib/store_attribute.rb +3 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2134f240621f2f546e5521fe4db4b66e3b6ec0a4a76ebb832fbcae8654c0904e
|
4
|
+
data.tar.gz: 862ce5201d0c1ad548035161b0f51b50a9a540a85ae8be0a9c550976f918701c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efe4992702c419f392f4fcbfd16c0ab32c862acf4679e841a7a8c28d40e0fb2eb66c2b72b2ac0156517a49bce4ee7308ec75ffa64604d4b879c735da0201d7f3
|
7
|
+
data.tar.gz: a9b8d3683abcd37f99a7c0ef68431e80e32a79537c5dab426e150a85b7d15c4b8ce1cb92e0a6c1c24031418286223e854fb2e2c73083c801781553f6559cd2c1
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,32 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 1.1.0 (2023-03-08) 🌷
|
6
|
+
|
7
|
+
- Add configuration option to return default values when attribute key is not present in the serialized value ([@markedmondson][], [@palkan][]).
|
8
|
+
|
9
|
+
Add to the class (preferrable `ApplicationRecord` or some other base class):
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
class ApplicationRecord < ActiveRecord::Base
|
13
|
+
self.store_attribute_unset_values_fallback_to_default = true
|
14
|
+
|
15
|
+
store_attribute :extra, :color, :string, default: "grey"
|
16
|
+
end
|
17
|
+
|
18
|
+
user = User.create!(extra: {})
|
19
|
+
# without the fallback
|
20
|
+
user.color #=> nil
|
21
|
+
# with fallback
|
22
|
+
user.color #=> "grey"
|
23
|
+
```
|
24
|
+
|
25
|
+
## 1.0.2 (2022-07-29)
|
26
|
+
|
27
|
+
- Fix possible conflicts with Active Model objects. ([@palkan][])
|
28
|
+
|
29
|
+
- Fix passing suffix/prefix to `store_accessor` without types. ([@palkan][])
|
30
|
+
|
5
31
|
## 1.0.1 (2022-05-05)
|
6
32
|
|
7
33
|
- Fixed suffix/prefix for predicates. ([@Alan-Marx](https://github.com/Alan-Marx))
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -36,7 +36,7 @@ Where:
|
|
36
36
|
- `store_name` The name of the store.
|
37
37
|
- `name` The name of the accessor to the store.
|
38
38
|
- `type` A symbol such as `:string` or `:integer`, or a type object to be used for the accessor.
|
39
|
-
- `options` (optional) A hash of cast type options such as `precision`, `limit`, `scale`, `default`.
|
39
|
+
- `options` (optional) A hash of cast type options such as `precision`, `limit`, `scale`, `default`. Regular `store_accessor` options, such as `prefix`, `suffix` are also supported.
|
40
40
|
|
41
41
|
Type casting occurs every time you write data through accessor or update store itself
|
42
42
|
and when object is loaded from database.
|
@@ -131,17 +131,30 @@ end
|
|
131
131
|
Date.current #=> 2022-03-17
|
132
132
|
|
133
133
|
user = User.new
|
134
|
-
user.name #=> "
|
134
|
+
user.name #=> "Joe"
|
135
135
|
user.expired_at #=> 2022-03-19
|
136
136
|
user.save!
|
137
137
|
|
138
138
|
raw_user = RawUser.find(user.id)
|
139
|
-
|
140
|
-
|
139
|
+
raw_user.name #=> "Joe"
|
140
|
+
raw_user.expired_at #=> 2022-03-19
|
141
141
|
|
142
142
|
another_raw_user = RawUser.create!
|
143
143
|
another_user = User.find(another_raw_user.id)
|
144
144
|
|
145
|
-
|
146
|
-
|
145
|
+
another_user.name #=> nil
|
146
|
+
another_user.expired_at #=> nil
|
147
147
|
```
|
148
|
+
|
149
|
+
It is possible to configure `store_attribute` to return the default value even when the record is persisted and the attribute name is not present. By using the `store_attribute_unset_values_fallback_to_default` class option, default values will be returned for missing keys. For example:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
class User < ApplicationRecord
|
153
|
+
self.store_attribute_unset_values_fallback_to_default = true
|
154
|
+
end
|
155
|
+
|
156
|
+
user = User.create!(extra: {})
|
157
|
+
user.expired_at #=> 2022-03-19
|
158
|
+
```
|
159
|
+
|
160
|
+
**IMPORTANT:** Due to implementation limitations, it's not recommended to toggle the value of `store_attribute_unset_values_fallback_to_default` in sub-classes. We recommend to set this value in base classes (e.g., `ApplicationRecord`).
|
@@ -4,6 +4,7 @@ module StoreAttribute
|
|
4
4
|
# Upgrade mutation tracker to return partial changes for typed stores
|
5
5
|
module MutationTracker
|
6
6
|
def change_to_attribute(attr_name)
|
7
|
+
return super unless attributes.is_a?(ActiveModel::AttributeSet)
|
7
8
|
return super unless attributes[attr_name].type.is_a?(ActiveRecord::Type::TypedStore)
|
8
9
|
|
9
10
|
orig_changes = super
|
@@ -10,6 +10,8 @@ module ActiveRecord
|
|
10
10
|
alias_method :_orig_store_without_types, :store
|
11
11
|
alias_method :_orig_store_accessor_without_types, :store_accessor
|
12
12
|
|
13
|
+
attr_writer :store_attribute_unset_values_fallback_to_default
|
14
|
+
|
13
15
|
# Defines store on this model.
|
14
16
|
#
|
15
17
|
# +store_name+ The name of the store.
|
@@ -60,7 +62,7 @@ module ActiveRecord
|
|
60
62
|
keys = keys.flatten
|
61
63
|
typed_keys = typed_keys.except(keys)
|
62
64
|
|
63
|
-
_orig_store_accessor_without_types(store_name, *(keys - typed_keys.keys), prefix:
|
65
|
+
_orig_store_accessor_without_types(store_name, *(keys - typed_keys.keys), prefix: prefix, suffix: suffix)
|
64
66
|
|
65
67
|
typed_keys.each do |key, type|
|
66
68
|
store_attribute(store_name, key, type, prefix: prefix, suffix: suffix)
|
@@ -125,6 +127,17 @@ module ActiveRecord
|
|
125
127
|
_store_local_stored_attribute(store_name, name, type, **options)
|
126
128
|
end
|
127
129
|
|
130
|
+
def store_attribute_unset_values_fallback_to_default
|
131
|
+
return @store_attribute_unset_values_fallback_to_default if instance_variable_defined?(:@store_attribute_unset_values_fallback_to_default)
|
132
|
+
|
133
|
+
@store_attribute_unset_values_fallback_to_default =
|
134
|
+
if superclass.respond_to?(:store_attribute_unset_values_fallback_to_default)
|
135
|
+
superclass.store_attribute_unset_values_fallback_to_default
|
136
|
+
else
|
137
|
+
false
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
128
141
|
def _store_local_stored_attribute(store_name, key, cast_type, default: Type::TypedStore::UNDEFINED, **options) # :nodoc:
|
129
142
|
cast_type = ActiveRecord::Type.lookup(cast_type, **options) if cast_type.is_a?(Symbol)
|
130
143
|
_local_typed_stored_attributes[store_name][key] = [cast_type, default]
|
@@ -156,10 +169,13 @@ module ActiveRecord
|
|
156
169
|
|
157
170
|
defaultik = Type::TypedStore::Defaultik.new
|
158
171
|
|
172
|
+
owner = self
|
173
|
+
|
159
174
|
if use_decorator
|
160
175
|
decorate_attribute_type(attr_name, "typed_accessor_for_#{attr_name}") do |subtype|
|
161
176
|
subtypes = _local_typed_stored_attributes[attr_name]
|
162
177
|
type = Type::TypedStore.create_from_type(subtype)
|
178
|
+
type.owner = owner
|
163
179
|
defaultik.type = type
|
164
180
|
subtypes.each { |name, (cast_type, default)| type.add_typed_key(name, cast_type, default: default) }
|
165
181
|
|
@@ -173,6 +189,7 @@ module ActiveRecord
|
|
173
189
|
subtype = _lookup_cast_type(attr_name, was_type, {}) if defined?(_lookup_cast_type)
|
174
190
|
|
175
191
|
type = Type::TypedStore.create_from_type(subtype)
|
192
|
+
type.owner = owner
|
176
193
|
defaultik.type = type
|
177
194
|
subtypes.each { |name, (cast_type, default)| type.add_typed_key(name, cast_type, default: default) }
|
178
195
|
|
@@ -25,6 +25,8 @@ module ActiveRecord
|
|
25
25
|
new(basetype)
|
26
26
|
end
|
27
27
|
|
28
|
+
attr_writer :owner
|
29
|
+
|
28
30
|
def initialize(subtype)
|
29
31
|
@accessor_types = {}
|
30
32
|
@defaults = {}
|
@@ -47,6 +49,8 @@ module ActiveRecord
|
|
47
49
|
accessor_types.each do |key, type|
|
48
50
|
if hash.key?(key)
|
49
51
|
hash[key] = type.deserialize(hash[key])
|
52
|
+
elsif fallback_to_default?(key)
|
53
|
+
hash[key] = built_defaults[key]
|
50
54
|
end
|
51
55
|
end
|
52
56
|
hash
|
@@ -106,6 +110,10 @@ module ActiveRecord
|
|
106
110
|
|
107
111
|
protected
|
108
112
|
|
113
|
+
def built_defaults
|
114
|
+
@built_defaults ||= build_defaults
|
115
|
+
end
|
116
|
+
|
109
117
|
# We cannot rely on string keys 'cause user input can contain symbol keys
|
110
118
|
def key_to_cast(val, key)
|
111
119
|
return key if val.key?(key)
|
@@ -121,7 +129,11 @@ module ActiveRecord
|
|
121
129
|
accessor_types.fetch(key.to_s)
|
122
130
|
end
|
123
131
|
|
124
|
-
|
132
|
+
def fallback_to_default?(key)
|
133
|
+
owner&.store_attribute_unset_values_fallback_to_default && defaults.key?(key)
|
134
|
+
end
|
135
|
+
|
136
|
+
attr_reader :accessor_types, :defaults, :store_accessor, :owner
|
125
137
|
end
|
126
138
|
end
|
127
139
|
end
|
data/lib/store_attribute.rb
CHANGED
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.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -106,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
106
106
|
- !ruby/object:Gem::Version
|
107
107
|
version: '0'
|
108
108
|
requirements: []
|
109
|
-
rubygems_version: 3.
|
109
|
+
rubygems_version: 3.4.6
|
110
110
|
signing_key:
|
111
111
|
specification_version: 4
|
112
112
|
summary: ActiveRecord extension which adds typecasting to store accessors
|