super_settings 0.0.0.rc1 → 0.0.1.rc1

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.
@@ -5,7 +5,7 @@ module SuperSettings
5
5
  # updating settings.
6
6
  #
7
7
  # This class does not deal with actually persisting settings to and fetching them from a data store.
8
- # You need to specify the storage engine you want to use with the `storage` class method. This gem
8
+ # You need to specify the storage engine you want to use with the +storage+ class method. This gem
9
9
  # ships with storage engines for ActiveRecord, Redis, and HTTP (microservice). See the SuperSettings::Storage
10
10
  # class for more details.
11
11
  class Setting
@@ -17,9 +17,8 @@ module SuperSettings
17
17
  BOOLEAN = "boolean"
18
18
  DATETIME = "datetime"
19
19
  ARRAY = "array"
20
- SECRET = "secret"
21
20
 
22
- VALUE_TYPES = [STRING, INTEGER, FLOAT, BOOLEAN, DATETIME, ARRAY, SECRET].freeze
21
+ VALUE_TYPES = [STRING, INTEGER, FLOAT, BOOLEAN, DATETIME, ARRAY].freeze
23
22
 
24
23
  ARRAY_DELIMITER = /[\n\r]+/.freeze
25
24
 
@@ -36,8 +35,8 @@ module SuperSettings
36
35
 
37
36
  class << self
38
37
  # Set a cache to use for caching values. This feature is optional. The cache must respond
39
- # to `delete(key)` and `fetch(key, &block)`. If you are running in a Rails environment,
40
- # you can use `Rails.cache` or any ActiveSupport::Cache::Store object.
38
+ # to +delete(key)+ and +fetch(key, &block)+. If you are running in a Rails environment,
39
+ # you can use +Rails.cache+ or any ActiveSupport::Cache::Store object.
41
40
  attr_accessor :cache
42
41
 
43
42
  # Set the storage class to use for persisting data.
@@ -56,6 +55,7 @@ module SuperSettings
56
55
  end
57
56
 
58
57
  # Create a new setting with the specified attributes.
58
+ #
59
59
  # @param attributes [Hash] hash of attribute names and values
60
60
  # @return [Setting]
61
61
  def create!(attributes)
@@ -68,6 +68,7 @@ module SuperSettings
68
68
 
69
69
  # Get all the settings. This will even return settings that have been marked as deleted.
70
70
  # If you just want current settings, then call #active instead.
71
+ #
71
72
  # @return [Array<Setting>]
72
73
  def all
73
74
  storage.with_connection do
@@ -76,6 +77,7 @@ module SuperSettings
76
77
  end
77
78
 
78
79
  # Get all the current settings.
80
+ #
79
81
  # @return [Array<Setting>]
80
82
  def active
81
83
  storage.with_connection do
@@ -84,6 +86,7 @@ module SuperSettings
84
86
  end
85
87
 
86
88
  # Get all settings that have been updated since the specified time stamp.
89
+ #
87
90
  # @param time [Time]
88
91
  # @return [Array<Setting>]
89
92
  def updated_since(time)
@@ -93,6 +96,7 @@ module SuperSettings
93
96
  end
94
97
 
95
98
  # Get a setting by its unique key.
99
+ #
96
100
  # @return Setting
97
101
  def find_by_key(key)
98
102
  record = storage.with_connection { storage.find_by_key(key) }
@@ -103,6 +107,7 @@ module SuperSettings
103
107
 
104
108
  # Return the maximum updated at value from all the rows. This is used in the caching
105
109
  # scheme to determine if data needs to be reloaded from the database.
110
+ #
106
111
  # @return [Time]
107
112
  def last_updated_at
108
113
  fetch_from_cache(LAST_UPDATED_CACHE_KEY) do
@@ -113,22 +118,20 @@ module SuperSettings
113
118
  # Bulk update settings in a single database transaction. No changes will be saved
114
119
  # if there are any invalid records.
115
120
  #
116
- # Example:
121
+ # @example
117
122
  #
118
- # ```
119
- # SuperSettings.bulk_update([
120
- # {
121
- # key: "setting-key",
122
- # value: "foobar",
123
- # value_type: "string",
124
- # description: "A sample setting"
125
- # },
126
- # {
127
- # key: "setting-to-delete",
128
- # deleted: true
129
- # }
130
- # ])
131
- # ```
123
+ # SuperSettings.bulk_update([
124
+ # {
125
+ # key: "setting-key",
126
+ # value: "foobar",
127
+ # value_type: "string",
128
+ # description: "A sample setting"
129
+ # },
130
+ # {
131
+ # key: "setting-to-delete",
132
+ # deleted: true
133
+ # }
134
+ # ])
132
135
  #
133
136
  # @param params [Array] Array of hashes with setting attributes. Each hash must include
134
137
  # a "key" element to identify the setting. To update a key, it must also include at least
@@ -136,7 +139,7 @@ module SuperSettings
136
139
  # the hash, it will be updated. If a setting with the given key does not exist, it will be created.
137
140
  # A setting may also be deleted by providing the attribute "deleted: true".
138
141
  # @return [Array] Boolean indicating if update succeeded, Array of settings affected by the update;
139
- # if the settings were not updated, the `errors` on the settings that failed validation will be filled.
142
+ # if the settings were not updated, the +errors+ on the settings that failed validation will be filled.
140
143
  def bulk_update(params, changed_by = nil)
141
144
  all_valid, settings = update_settings(params, changed_by)
142
145
  if all_valid
@@ -153,6 +156,8 @@ module SuperSettings
153
156
  end
154
157
 
155
158
  # Determine the value type from a value.
159
+ #
160
+ # @return [String]
156
161
  def value_type(value)
157
162
  case value
158
163
  when Integer
@@ -171,6 +176,7 @@ module SuperSettings
171
176
  end
172
177
 
173
178
  # Clear the last updated timestamp from the cache.
179
+ #
174
180
  # @api private
175
181
  def clear_last_updated_cache
176
182
  cache&.delete(Setting::LAST_UPDATED_CACHE_KEY)
@@ -179,8 +185,9 @@ module SuperSettings
179
185
  private
180
186
 
181
187
  # Updates settings in memory from an array of parameters.
182
- # @param params [Array<Hash>] Each hash must contain a `key` element and may contain elements
183
- # for `value`, `value_type`, `description`, and `deleted`.
188
+ #
189
+ # @param params [Array<Hash>] Each hash must contain a "key" element and may contain elements
190
+ # for "value", "value_type", "description", and "deleted".
184
191
  # @param changed_by [String] Value to be stored in the history for each setting
185
192
  # @return [Array] The first value is a boolean indicating if all the settings are valid,
186
193
  # the second is an array of settings with their attributes updated in memory and ready to be saved.
@@ -247,20 +254,25 @@ module SuperSettings
247
254
  end
248
255
  end
249
256
 
250
- # @return [String] the unique key for the setting.
257
+ # Get the unique key for the setting.
258
+ #
259
+ # @return [String]
251
260
  def key
252
261
  @record.key
253
262
  end
254
263
 
255
- # Set the value of the setting.
256
- # @param val [String]
264
+ # Set the value of the setting. The value will be coerced to a string for storage.
265
+ #
266
+ # @param val [Object]
257
267
  def key=(val)
258
268
  val = val&.to_s
259
269
  will_change!(:key, val) unless key == val
260
270
  @record.key = val
261
271
  end
262
272
 
263
- # @return [Object] the value of a setting coerced to the appropriate class depending on its value type.
273
+ # The value of a setting coerced to the appropriate class depending on its value type.
274
+ #
275
+ # @return [Object]
264
276
  def value
265
277
  if deleted?
266
278
  nil
@@ -270,6 +282,7 @@ module SuperSettings
270
282
  end
271
283
 
272
284
  # Set the value of the setting.
285
+ #
273
286
  # @param val [Object]
274
287
  def value=(val)
275
288
  val = serialize(val) unless val.is_a?(Array)
@@ -277,22 +290,31 @@ module SuperSettings
277
290
  self.raw_value = val
278
291
  end
279
292
 
293
+ # Get the type of value being stored in the setting.
294
+ #
295
+ # @return [String] one of string, integer, float, boolean, datetime, or array.
280
296
  def value_type
281
297
  @record.value_type
282
298
  end
283
299
 
284
300
  # Set the value type of the setting.
285
- # @param val [String] one of string, integer, float, boolean, datetime, array, or secret.
301
+ #
302
+ # @param val [String] one of string, integer, float, boolean, datetime, or array.
286
303
  def value_type=(val)
287
304
  val = val&.to_s
288
305
  will_change!(:value_type, val) unless value_type == val
289
306
  @record.value_type = val
290
307
  end
291
308
 
309
+ # Get the description for the setting.
310
+ #
311
+ # @return [String]
292
312
  def description
293
313
  @record.description
294
314
  end
295
315
 
316
+ # Set the description of the setting.
317
+ #
296
318
  # @param val [String]
297
319
  def description=(val)
298
320
  val = val&.to_s
@@ -301,6 +323,9 @@ module SuperSettings
301
323
  @record.description = val
302
324
  end
303
325
 
326
+ # Return true if the setting has been marked as deleted.
327
+ #
328
+ # @return [Boolean]
304
329
  def deleted?
305
330
  @record.deleted?
306
331
  end
@@ -309,6 +334,7 @@ module SuperSettings
309
334
 
310
335
  # Set the deleted flag on the setting. Deleted settings are not visible but are not actually
311
336
  # removed from the data store.
337
+ #
312
338
  # @param val [Boolean]
313
339
  def deleted=(val)
314
340
  val = Coerce.boolean(val)
@@ -316,10 +342,15 @@ module SuperSettings
316
342
  @record.deleted = val
317
343
  end
318
344
 
345
+ # Get the time the setting was first created.
346
+ #
347
+ # @return [Time]
319
348
  def created_at
320
349
  @record.created_at
321
350
  end
322
351
 
352
+ # Set the time when the setting was created.
353
+ #
323
354
  # @param val [Time, DateTime]
324
355
  def created_at=(val)
325
356
  val = Coerce.time(val)
@@ -327,10 +358,15 @@ module SuperSettings
327
358
  @record.created_at = val
328
359
  end
329
360
 
361
+ # Get the time the setting was last updated.
362
+ #
363
+ # @return [Time]
330
364
  def updated_at
331
365
  @record.updated_at
332
366
  end
333
367
 
368
+ # Set the time when the setting was last updated.
369
+ #
334
370
  # @param val [Time, DateTime]
335
371
  def updated_at=(val)
336
372
  val = Coerce.time(val)
@@ -338,50 +374,49 @@ module SuperSettings
338
374
  @record.updated_at = val
339
375
  end
340
376
 
341
- # @return [true] if the setting has a string value type.
377
+ # Return true if the setting has a string value type.
378
+ #
379
+ # @return [Boolean]
342
380
  def string?
343
381
  value_type == STRING
344
382
  end
345
383
 
346
- # @return [true] if the setting has an integer value type.
384
+ # Return true if the setting has an integer value type.
385
+ #
386
+ # @return [Boolean]
347
387
  def integer?
348
388
  value_type == INTEGER
349
389
  end
350
390
 
351
- # @return [true] if the setting has a float value type.
391
+ # Return true if the setting has a float value type.
392
+ # @return [Boolean]
352
393
  def float?
353
394
  value_type == FLOAT
354
395
  end
355
396
 
356
- # @return [true] if the setting has a boolean value type.
397
+ # Return true if the setting has a boolean value type.
398
+ # @return [Boolean]
357
399
  def boolean?
358
400
  value_type == BOOLEAN
359
401
  end
360
402
 
361
- # @return [true] if the setting has a datetime value type.
403
+ # Return true if the setting has a datetime value type.
404
+ # @return [Boolean]
362
405
  def datetime?
363
406
  value_type == DATETIME
364
407
  end
365
408
 
366
- # @return [true] if the setting has an array value type.
409
+ # Return true if the setting has an array value type.
410
+ # @return [Boolean]
367
411
  def array?
368
412
  value_type == ARRAY
369
413
  end
370
414
 
371
- # @return [true] if the setting has a secret value type.
372
- def secret?
373
- value_type == SECRET
374
- end
375
-
376
- # @return [true] if the setting is a secret setting and the value is encrypted in the database.
377
- def encrypted?
378
- secret? && Encryption.encrypted?(raw_value)
379
- end
380
-
381
415
  # Save the setting to the data storage engine.
416
+ #
382
417
  # @return [void]
383
418
  def save!
384
- set_raw_value
419
+ record_value_change
385
420
 
386
421
  unless valid?
387
422
  raise InvalidRecordError.new(errors.values.join("; "))
@@ -398,7 +433,6 @@ module SuperSettings
398
433
 
399
434
  begin
400
435
  self.class.clear_last_updated_cache
401
- redact_history! if history_needs_redacting?
402
436
  ensure
403
437
  clear_changes
404
438
  end
@@ -406,27 +440,36 @@ module SuperSettings
406
440
  nil
407
441
  end
408
442
 
409
- # @return [Boolean] true if the record has been stored in the data storage engine.
443
+ # Return true if the record has been stored in the data storage engine.
444
+ #
445
+ # @return [Boolean]
410
446
  def persisted?
411
447
  @record.persisted?
412
448
  end
413
449
 
414
- # @return [Boolean] true if the record has valid data.
450
+ # Return true if the record has valid data.
451
+ #
452
+ # @return [Boolean]
415
453
  def valid?
416
454
  validate!
417
455
  @errors.empty?
418
456
  end
419
457
 
420
- # @return [Hash<String, Array<String>>] hash of errors generated from the last call to `valid?`
458
+ # Return hash of errors generated from the last call to +valid?+
459
+ #
460
+ # @return [Hash<String, Array<String>>]
421
461
  attr_reader :errors
422
462
 
423
463
  # Mark the record as deleted. The record will not actually be deleted since it's still needed
424
464
  # for caching purposes, but it will no longer be returned by queries.
465
+ #
466
+ # @return [void]
425
467
  def delete!
426
468
  update!(deleted: true)
427
469
  end
428
470
 
429
471
  # Update the setting attributes and save it.
472
+ #
430
473
  # @param attributes [Hash]
431
474
  # @return [void]
432
475
  def update!(attributes)
@@ -436,12 +479,14 @@ module SuperSettings
436
479
 
437
480
  # Return array of history items reflecting changes made to the setting over time. Items
438
481
  # should be returned in reverse chronological order so that the most recent changes are first.
482
+ #
439
483
  # @return [Array<SuperSettings::History>]
440
484
  def history(limit: nil, offset: 0)
441
485
  @record.history(limit: limit, offset: offset)
442
486
  end
443
487
 
444
488
  # Serialize to a hash that is used for rendering JSON responses.
489
+ #
445
490
  # @return [Hash]
446
491
  def as_json(options = nil)
447
492
  attributes = {
@@ -452,12 +497,12 @@ module SuperSettings
452
497
  created_at: created_at,
453
498
  updated_at: updated_at
454
499
  }
455
- attributes[:encrypted] = encrypted? if secret?
456
500
  attributes[:deleted] = true if deleted?
457
501
  attributes
458
502
  end
459
503
 
460
504
  # Serialize to a JSON string.
505
+ #
461
506
  # @return [String]
462
507
  def to_json(options = nil)
463
508
  as_json.to_json(options)
@@ -486,12 +531,6 @@ module SuperSettings
486
531
  else
487
532
  Array(value).reject { |v| v.respond_to?(:empty?) ? v.empty? : v.to_s.empty? }.collect { |v| v.to_s.freeze }.freeze
488
533
  end
489
- when Setting::SECRET
490
- begin
491
- Encryption.decrypt(value).freeze
492
- rescue Encryption::InvalidSecretError
493
- nil
494
- end
495
534
  else
496
535
  value.freeze
497
536
  end
@@ -510,18 +549,10 @@ module SuperSettings
510
549
  end
511
550
  end
512
551
 
513
- # Set the raw string value that will be persisted to the data store.
514
- def set_raw_value
515
- if value_type == Setting::SECRET && !raw_value.to_s.empty? && (changed?(:raw_value) || !Encryption.encrypted?(raw_value))
516
- self.raw_value = Encryption.encrypt(raw_value)
517
- end
518
- record_value_change
519
- end
520
-
521
552
  # Update the histories association whenever the value or key is changed.
522
553
  def record_value_change
523
554
  return unless changed?(:raw_value) || changed?(:deleted) || changed?(:key)
524
- recorded_value = (deleted? || value_type == Setting::SECRET ? nil : raw_value)
555
+ recorded_value = (deleted? ? nil : raw_value)
525
556
  @record.create_history(value: recorded_value, deleted: deleted?, changed_by: changed_by, created_at: Time.now)
526
557
  end
527
558
 
@@ -544,14 +575,6 @@ module SuperSettings
544
575
  @changes.include?(attribute.to_s)
545
576
  end
546
577
 
547
- def history_needs_redacting?
548
- value_type == Setting::SECRET && changed?(:value_type)
549
- end
550
-
551
- def redact_history!
552
- @record.send(:redact_history!)
553
- end
554
-
555
578
  def raw_value=(val)
556
579
  val = val&.to_s
557
580
  val = nil if val&.empty?
@@ -4,9 +4,11 @@ module SuperSettings
4
4
  module Storage
5
5
  # ActiveRecord implementation of the SuperSettings::Storage model.
6
6
  #
7
- # To use this model, you must run the migration included with the gem. The migration
8
- # can be installed with `rake app:super_settings:install:migrations` if the gem is mounted
9
- # as an engine in a Rails application.
7
+ # To use this model, you must run the migration included with the gem. If the gem
8
+ # is mounted as an engine in a Rails applicationThe migration can be installed with
9
+ #
10
+ # @example
11
+ # rake app:super_settings:install:migrations
10
12
  class ActiveRecordStorage
11
13
  # Base class that the models extend from.
12
14
  class ApplicationRecord < ActiveRecord::Base
@@ -85,7 +87,7 @@ module SuperSettings
85
87
  end
86
88
 
87
89
  delegate :key, :key=, :raw_value, :raw_value=, :value_type, :value_type=, :description, :description=,
88
- :deleted?, :deleted=, :updated_at, :updated_at=, :created_at, :created_at=, :persisted?, :save!,
90
+ :deleted?, :deleted=, :updated_at, :updated_at=, :created_at, :created_at=, :persisted?,
89
91
  to: :@model
90
92
 
91
93
  def initialize(attributes = {})
@@ -96,6 +98,28 @@ module SuperSettings
96
98
  end
97
99
  end
98
100
 
101
+ def save!
102
+ begin
103
+ @model.save!
104
+ rescue ActiveRecord::RecordNotUnique => e
105
+ # Gracefully handle duplicate key constraint on the database; in this case the existing
106
+ # record should be updated.
107
+ duplicate = @model.class.find_by(key: @model.key)
108
+ raise e if duplicate == @model
109
+ duplicate.raw_value = @model.raw_value
110
+ duplicate.value_type = @model.value_type
111
+ duplicate.description = @model.description
112
+ duplicate.deleted = false
113
+ @model.transaction do
114
+ if @model.persisted?
115
+ @model.reload.update!(deleted: true)
116
+ end
117
+ duplicate.save!
118
+ end
119
+ @model = duplicate
120
+ end
121
+ end
122
+
99
123
  def history(limit: nil, offset: 0)
100
124
  finder = @model.history_items.order(id: :desc).offset(offset)
101
125
  finder = finder.limit(limit) if limit
@@ -112,12 +136,6 @@ module SuperSettings
112
136
  @model.history_items.build(history_attributes)
113
137
  end
114
138
  end
115
-
116
- protected
117
-
118
- def redact_history!
119
- @model.history_items.update_all(value: nil)
120
- end
121
139
  end
122
140
  end
123
141
  end
@@ -3,11 +3,11 @@
3
3
  require "json"
4
4
  require "net/http"
5
5
 
6
- # SuperSettings::Storage model that reads from a remote service running the SuperSettings REST API.
7
- # This storage engine is read only. It is intended to allow microservices to read settings from a
8
- # central application that exposes the SuperSettings::RestAPI.
9
6
  module SuperSettings
10
7
  module Storage
8
+ # SuperSettings::Storage model that reads from a remote service running the SuperSettings REST API.
9
+ # This storage engine is read only. It is intended to allow microservices to read settings from a
10
+ # central application that exposes the SuperSettings::RestAPI.
11
11
  class HttpStorage
12
12
  include Storage
13
13
 
@@ -92,14 +92,14 @@ module SuperSettings
92
92
  private
93
93
 
94
94
  def call_api(method, path, params = {})
95
- url_params = (method == :get ? query_params.merge(params) : query_params)
95
+ url_params = ((method == :get) ? query_params.merge(params) : query_params)
96
96
  uri = api_uri(path, url_params)
97
97
 
98
98
  body = nil
99
99
  request_headers = DEFAULT_HEADERS.merge(headers)
100
100
  if method == :post && !params&.empty?
101
101
  body = params.to_json
102
- request_headers["Content-Type"] = "application/json; charset=utf8-"
102
+ request_headers["content-type"] = "application/json; charset=utf8-"
103
103
  end
104
104
 
105
105
  response = http_request(method: method, uri: uri, headers: request_headers, body: body)
@@ -131,7 +131,7 @@ module SuperSettings
131
131
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
132
132
  end
133
133
 
134
- request = (method == :post ? Net::HTTP::Post.new(uri.request_uri) : Net::HTTP::Get.new(uri.request_uri))
134
+ request = ((method == :post) ? Net::HTTP::Post.new(uri.request_uri) : Net::HTTP::Get.new(uri.request_uri))
135
135
  set_headers(request, headers)
136
136
  request.body = body if body
137
137
 
@@ -144,7 +144,7 @@ module SuperSettings
144
144
  end
145
145
 
146
146
  if response.is_a?(Net::HTTPRedirection)
147
- location = resp["Location"]
147
+ location = resp["location"]
148
148
  if redirect_count < 5 && SuperSettings::Coerce.present?(location)
149
149
  return http_request(method: :get, uri: URI(location), headers: headers, body: body, redirect_count: redirect_count + 1)
150
150
  end
@@ -255,12 +255,6 @@ module SuperSettings
255
255
  !!(defined?(@persisted) && @persisted)
256
256
  end
257
257
 
258
- protected
259
-
260
- def redact_history!
261
- # No-op since history is maintained by the source system.
262
- end
263
-
264
258
  private
265
259
 
266
260
  def set_persisted!
@@ -270,10 +264,6 @@ module SuperSettings
270
264
  def call_api(method, path, params = {})
271
265
  self.class.send(:call_api, method, path, params)
272
266
  end
273
-
274
- def encrypted=(value)
275
- # No op; needed for API compatibility
276
- end
277
267
  end
278
268
  end
279
269
  end
@@ -2,27 +2,26 @@
2
2
 
3
3
  require "json"
4
4
 
5
- # Redis implementation of the SuperSettings::Storage model.
6
- #
7
- # You must define the redis connection to use by setting the redis attribute on the class.
8
- # This can either be a `Redis` object or a block that yields a `Redis` object. You can use the
9
- # block form if you need to get the `Redis` object at runtime instead of having a static object.
10
- #
11
- # ```ruby
12
- # SuperSettings::Storage::RedisStorage.redis = Redis.new(url: ENV["REDIS_URL"])
13
- #
14
- # SuperSettings::Storage::RedisStorage.redis = lambda { RedisClient.get(:settings) }
15
- # ```
16
- #
17
- # You can also use the [connection_pool]() gem to provide a pool of Redis connecions for
18
- # a multi-threaded application. The connection_pool gem is not a dependency of this gem,
19
- # so you would need to add it to your application dependencies to use it.
20
- #
21
- # ```ruby
22
- # SuperSettings::Storage::RedisStorage.redis = ConnectionPool.new(size: 5) { Redis.new(url: ENV["REDIS_URL"]) }
23
- # ```
24
5
  module SuperSettings
25
6
  module Storage
7
+ # Redis implementation of the SuperSettings::Storage model.
8
+ #
9
+ # You must define the redis connection to use by setting the redis attribute on the class.
10
+ # This can either be a +Redis+ object or a block that yields a +Redis+ object. You can use the
11
+ # block form if you need to get the Redis object at runtime instead of having a static object.
12
+ #
13
+ # You can also use the [connection_pool]() gem to provide a pool of Redis connecions for
14
+ # a multi-threaded application. The connection_pool gem is not a dependency of this gem,
15
+ # so you would need to add it to your application dependencies to use it.
16
+ #
17
+ # @example
18
+ # SuperSettings::Storage::RedisStorage.redis = Redis.new(url: ENV["REDIS_URL"])
19
+ #
20
+ # @example
21
+ # SuperSettings::Storage::RedisStorage.redis = lambda { RedisClient.get(:settings) }
22
+ #
23
+ # @example
24
+ # SuperSettings::Storage::RedisStorage.redis = ConnectionPool.new(size: 5) { Redis.new(url: ENV["REDIS_URL"]) }
26
25
  class RedisStorage
27
26
  include Storage
28
27
 
@@ -122,7 +121,8 @@ module SuperSettings
122
121
  def find_by_key(key)
123
122
  json = with_redis { |redis| redis.hget(SETTINGS_KEY, key) }
124
123
  return nil unless json
125
- load_from_json(json)
124
+ record = load_from_json(json)
125
+ record unless record.deleted?
126
126
  end
127
127
 
128
128
  def last_updated_at
@@ -249,19 +249,6 @@ module SuperSettings
249
249
  !!(defined?(@persisted) && @persisted)
250
250
  end
251
251
 
252
- protected
253
-
254
- def redact_history!
255
- after_commit do
256
- histories = HistoryStorage.find_all_by_key(key: key)
257
- histories.each { |item| item.value = nil }
258
- self.class.transaction do
259
- HistoryStorage.destroy_all_by_key(key)
260
- histories.reverse.each(&:save!)
261
- end
262
- end
263
- end
264
-
265
252
  private
266
253
 
267
254
  def after_commit(&block)