store_attribute 1.0.2 → 1.1.0

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: 076f7b987e61b6d32a5ee894f42d9ac85cf226df332400ff133bc492e4a4c184
4
- data.tar.gz: 94fcf6d42c30e98888b8a9a7f7af880c1c2e3d0cabf25fc0e63b84e41d6e0f28
3
+ metadata.gz: 2134f240621f2f546e5521fe4db4b66e3b6ec0a4a76ebb832fbcae8654c0904e
4
+ data.tar.gz: 862ce5201d0c1ad548035161b0f51b50a9a540a85ae8be0a9c550976f918701c
5
5
  SHA512:
6
- metadata.gz: 6ddff720796fe0c048712b846cdf1bebe54dfdaea59d93d1fbe59557fc263156e53955fb2ee8aef0cea840b7e50f629f193ae2da8a7580108c7c466781341b1f
7
- data.tar.gz: 0e6d69b002d492fd4619b4fd4f24eddabbc5e06332c6a597d6b292f7c0cdcb565b4189f63f5bef9e342e40cf20d585d7508b2fc54cc9c0b4dc1f2763ca3bdf7d
6
+ metadata.gz: efe4992702c419f392f4fcbfd16c0ab32c862acf4679e841a7a8c28d40e0fb2eb66c2b72b2ac0156517a49bce4ee7308ec75ffa64604d4b879c735da0201d7f3
7
+ data.tar.gz: a9b8d3683abcd37f99a7c0ef68431e80e32a79537c5dab426e150a85b7d15c4b8ce1cb92e0a6c1c24031418286223e854fb2e2c73083c801781553f6559cd2c1
data/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
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
+
5
25
  ## 1.0.2 (2022-07-29)
6
26
 
7
27
  - Fix possible conflicts with Active Model objects. ([@palkan][])
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2016-2020 palkan
1
+ Copyright 2016-2023 palkan
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
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 #=> "john"
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
- user.name #=> "john"
140
- user.expired_at #=> 2022-03-19
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
- user.name #=> nil
146
- user.expired_at #=> nil
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`).
@@ -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.
@@ -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
- attr_reader :accessor_types, :defaults, :store_accessor
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StoreAttribute # :nodoc:
4
- VERSION = "1.0.2"
4
+ VERSION = "1.1.0"
5
5
  end
@@ -2,3 +2,6 @@
2
2
 
3
3
  require "store_attribute/version"
4
4
  require "store_attribute/active_record"
5
+
6
+ module StoreAttribute
7
+ 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.0.2
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: 2022-07-30 00:00:00.000000000 Z
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.3.7
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