super_settings 0.0.0.rc1 → 0.0.1.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)