Class: SuperSettings::Setting
- Inherits:
-
Object
- Object
- SuperSettings::Setting
- Includes:
- Attributes
- Defined in:
- lib/super_settings/setting.rb
Overview
This is the model for interacting with settings. This class provides methods for finding, validating, and updating settings.
This class does not deal with actually persisting settings to and fetching them from a data store.
You need to specify the storage engine you want to use with the storage class method. This gem
ships with storage engines for ActiveRecord, Redis, and HTTP (microservice). See the SuperSettings::Storage
class for more details.
Defined Under Namespace
Classes: InvalidRecordError, PersistenceError
Constant Summary collapse
- LAST_UPDATED_CACHE_KEY =
Cache key used for storing the last updated timestamp.
"SuperSettings.last_updated_at"- STRING =
"string"- INTEGER =
"integer"- FLOAT =
"float"- BOOLEAN =
"boolean"- DATETIME =
"datetime"- ARRAY =
"array"- VALUE_TYPES =
[STRING, INTEGER, FLOAT, BOOLEAN, DATETIME, ARRAY].freeze
- ARRAY_DELIMITER =
/[\n\r]+/.freeze
Class Attribute Summary collapse
-
.after_save_blocks ⇒ Object
readonly
Returns the value of attribute after_save_blocks.
-
.cache ⇒ Object
Set a cache to use for caching values.
-
.storage ⇒ Class
private
The storage class to use for persisting data.
Instance Attribute Summary collapse
-
#changed_by ⇒ Object
The changed_by attribute is used to temporarily store an identifier for the user who made a change to a setting to be stored in the history table.
-
#errors ⇒ Hash<String, Array<String>>
readonly
Return hash of errors generated from the last call to
valid?.
Class Method Summary collapse
-
.active ⇒ Array<Setting>
Get all the current settings.
-
.add_record_to_transaction(record) ⇒ Object
private
Add a record to the current transaction.
-
.after_save {|setting| ... } ⇒ Object
Add a block of code that will be called when a setting is saved.
-
.all ⇒ Array<Setting>
Get all the settings.
-
.bulk_update(params, changed_by = nil) ⇒ Array
Bulk update settings in a single database transaction.
-
.clear_last_updated_cache ⇒ Object
private
Clear the last updated timestamp from the cache.
-
.create!(attributes) ⇒ Setting
Create a new setting with the specified attributes.
-
.find_by_key(key) ⇒ Object
Get a setting by its unique key.
-
.last_updated_at ⇒ Time
Return the maximum updated at value from all the rows.
-
.transaction(&block) ⇒ Object
private
Wrap a block of code in a transaction.
-
.updated_since(time) ⇒ Array<Setting>
Get all settings that have been updated since the specified time stamp.
-
.value_type(value) ⇒ String
Determine the value type from a value.
Instance Method Summary collapse
-
#array? ⇒ Boolean
Return true if the setting has an array value type.
-
#as_json(options = nil) ⇒ Hash
Serialize to a hash that is used for rendering JSON responses.
-
#boolean? ⇒ Boolean
Return true if the setting has a boolean value type.
-
#changes ⇒ Hash<String, Array>
Get hash of attribute changes.
-
#created_at ⇒ Time
Get the time the setting was first created.
-
#created_at=(val) ⇒ Object
Set the time when the setting was created.
-
#datetime? ⇒ Boolean
Return true if the setting has a datetime value type.
-
#delete! ⇒ void
Mark the record as deleted.
-
#deleted=(val) ⇒ Object
Set the deleted flag on the setting.
-
#deleted? ⇒ Boolean
(also: #deleted)
Return true if the setting has been marked as deleted.
-
#description ⇒ String
Get the description for the setting.
-
#description=(val) ⇒ Object
Set the description of the setting.
-
#float? ⇒ Boolean
Return true if the setting has a float value type.
-
#history(limit: nil, offset: 0) ⇒ Array<SuperSettings::History>
Return array of history items reflecting changes made to the setting over time.
-
#initialize(attributes = {}) ⇒ Setting
constructor
A new instance of Setting.
-
#integer? ⇒ Boolean
Return true if the setting has an integer value type.
-
#key ⇒ String
Get the unique key for the setting.
-
#key=(val) ⇒ Object
Set the value of the setting.
-
#persisted? ⇒ Boolean
Return true if the record has been stored in the data storage engine.
-
#save! ⇒ void
Save the setting to the data storage engine.
-
#string? ⇒ Boolean
Return true if the setting has a string value type.
-
#to_json(options = nil) ⇒ String
Serialize to a JSON string.
-
#update!(attributes) ⇒ void
Update the setting attributes and save it.
-
#updated_at ⇒ Time
Get the time the setting was last updated.
-
#updated_at=(val) ⇒ Object
Set the time when the setting was last updated.
-
#valid? ⇒ Boolean
Return true if the record has valid data.
-
#value ⇒ Object
The value of a setting coerced to the appropriate class depending on its value type.
-
#value=(val) ⇒ Object
Set the value of the setting.
-
#value_changed? ⇒ Boolean
Return true if the value of the setting has changed.
-
#value_type ⇒ String
Get the type of value being stored in the setting.
-
#value_type=(val) ⇒ Object
Set the value type of the setting.
Methods included from Attributes
Constructor Details
#initialize(attributes = {}) ⇒ Setting
Returns a new instance of Setting.
324 325 326 327 328 329 330 331 332 333 334 |
# File 'lib/super_settings/setting.rb', line 324 def initialize(attributes = {}) @changes = {} @errors = {} if attributes.is_a?(Storage) @record = attributes else @record = self.class.storage.new self.attributes = attributes self.value_type ||= STRING end end |
Class Attribute Details
.after_save_blocks ⇒ Object (readonly)
Returns the value of attribute after_save_blocks.
56 57 58 |
# File 'lib/super_settings/setting.rb', line 56 def after_save_blocks @after_save_blocks end |
.cache ⇒ Object
Set a cache to use for caching values. This feature is optional. The cache must respond
to delete(key) and fetch(key, &block). If you are running in a Rails environment,
you can use Rails.cache or any ActiveSupport::Cache::Store object.
51 52 53 |
# File 'lib/super_settings/setting.rb', line 51 def cache @cache end |
.storage ⇒ Class
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns The storage class to use for persisting data.
60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/super_settings/setting.rb', line 60 def storage if @storage == NOT_SET if defined?(ActiveRecord) && defined?(::SuperSettings::Storage::ActiveRecordStorage) ::SuperSettings::Storage::ActiveRecordStorage else raise ArgumentError.new("No storage class defined for #{name}") end else @storage end end |
Instance Attribute Details
#changed_by ⇒ Object
The changed_by attribute is used to temporarily store an identifier for the user who made a change to a setting to be stored in the history table. This value is optional and is cleared after the record is saved.
42 43 44 |
# File 'lib/super_settings/setting.rb', line 42 def changed_by @changed_by end |
#errors ⇒ Hash<String, Array<String>> (readonly)
Return hash of errors generated from the last call to valid?
536 537 538 |
# File 'lib/super_settings/setting.rb', line 536 def errors @errors end |
Class Method Details
.active ⇒ Array<Setting>
Get all the current settings.
106 107 108 109 110 |
# File 'lib/super_settings/setting.rb', line 106 def active storage.with_connection do storage.active.collect { |record| new(record) } end end |
.add_record_to_transaction(record) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Add a record to the current transaction.
248 249 250 251 |
# File 'lib/super_settings/setting.rb', line 248 def add_record_to_transaction(record) changes = Thread.current[:super_settings_transaction] changes << record if changes end |
.after_save {|setting| ... } ⇒ Object
Add a block of code that will be called when a setting is saved. The block will be
called with a Setting object. The object will have been saved, but the changes
hash will still be set indicating what was changed. You can define multiple after_save blocks.
77 78 79 |
# File 'lib/super_settings/setting.rb', line 77 def after_save(&block) after_save_blocks << block end |
.all ⇒ Array<Setting>
Get all the settings. This will even return settings that have been marked as deleted. If you just want current settings, then call #active instead.
97 98 99 100 101 |
# File 'lib/super_settings/setting.rb', line 97 def all storage.with_connection do storage.all.collect { |record| new(record) } end end |
.bulk_update(params, changed_by = nil) ⇒ Array
Bulk update settings in a single database transaction. No changes will be saved if there are any invalid records.
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/super_settings/setting.rb', line 168 def bulk_update(params, changed_by = nil) all_valid, settings = update_settings(params, changed_by) if all_valid begin storage.with_connection do transaction do |_changes| settings.each do |setting| setting.save! end end end rescue InvalidRecordError, PersistenceError => e # Validation failures detected by save! are already recorded on the setting that # failed. A storage level failure isn't attributable to any single setting, so # record it on all of them; otherwise callers would get a failure with no # explanation of what went wrong. if settings.none? { |setting| setting.errors.any? } settings.each { |setting| setting.send(:add_base_error, e.) } end return [false, settings] end clear_last_updated_cache end [all_valid, settings] end |
.clear_last_updated_cache ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Clear the last updated timestamp from the cache.
217 218 219 |
# File 'lib/super_settings/setting.rb', line 217 def clear_last_updated_cache cache&.delete(Setting::LAST_UPDATED_CACHE_KEY) end |
.create!(attributes) ⇒ Setting
Create a new setting with the specified attributes.
85 86 87 88 89 90 91 |
# File 'lib/super_settings/setting.rb', line 85 def create!(attributes) setting = new(attributes) storage.with_connection do setting.save! end setting end |
.find_by_key(key) ⇒ Object
Get a setting by its unique key.
126 127 128 129 130 131 |
# File 'lib/super_settings/setting.rb', line 126 def find_by_key(key) record = storage.with_connection { storage.find_by_key(key) } if record new(record) end end |
.last_updated_at ⇒ Time
Return the maximum updated at value from all the rows. This is used in the caching scheme to determine if data needs to be reloaded from the database.
137 138 139 140 141 |
# File 'lib/super_settings/setting.rb', line 137 def last_updated_at fetch_from_cache(LAST_UPDATED_CACHE_KEY) do storage.with_connection { storage.last_updated_at } end end |
.transaction(&block) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Wrap a block of code in a transaction.
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/super_settings/setting.rb', line 224 def transaction(&block) changes = Thread.current[:super_settings_transaction] return yield if changes changes = [] Thread.current[:super_settings_transaction] = changes begin storage.transaction(&block) clear_last_updated_cache changes.each do |setting| setting.send(:call_after_save_callbacks) setting.send(:clear_changes) end ensure Thread.current[:super_settings_transaction] = nil end end |
.updated_since(time) ⇒ Array<Setting>
Get all settings that have been updated since the specified time stamp.
116 117 118 119 120 121 |
# File 'lib/super_settings/setting.rb', line 116 def updated_since(time) time = SuperSettings::Coerce.time(time) storage.with_connection do storage.updated_since(time).collect { |record| new(record) } end end |
.value_type(value) ⇒ String
Determine the value type from a value.
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/super_settings/setting.rb', line 197 def value_type(value) case value when Integer INTEGER when Numeric FLOAT when TrueClass, FalseClass BOOLEAN when Time, Date DATETIME when Array ARRAY else STRING end end |
Instance Method Details
#array? ⇒ Boolean
Return true if the setting has an array value type.
490 491 492 |
# File 'lib/super_settings/setting.rb', line 490 def array? value_type == ARRAY end |
#as_json(options = nil) ⇒ Hash
Serialize to a hash that is used for rendering JSON responses.
567 568 569 570 571 572 573 574 575 576 577 578 |
# File 'lib/super_settings/setting.rb', line 567 def as_json( = nil) attributes = { key: key, value: value, value_type: value_type, description: description, created_at: created_at&.utc&.iso8601(6), updated_at: updated_at&.utc&.iso8601(6) } attributes[:deleted] = true if deleted? attributes end |
#boolean? ⇒ Boolean
Return true if the setting has a boolean value type.
478 479 480 |
# File 'lib/super_settings/setting.rb', line 478 def boolean? value_type == BOOLEAN end |
#changes ⇒ Hash<String, Array>
Get hash of attribute changes. The hash keys are the names of attributes that have changed and the values are an array with [old value, new value]. The keys will be one of key, raw_value, value_type, description, deleted, created_at, or updated_at.
593 594 595 |
# File 'lib/super_settings/setting.rb', line 593 def changes @changes.dup end |
#created_at ⇒ Time
Get the time the setting was first created.
427 428 429 |
# File 'lib/super_settings/setting.rb', line 427 def created_at @record.created_at end |
#created_at=(val) ⇒ Object
Set the time when the setting was created.
434 435 436 437 438 |
# File 'lib/super_settings/setting.rb', line 434 def created_at=(val) val = TimePrecision.new(val).time will_change!(:created_at, val) unless created_at == val @record.created_at = val end |
#datetime? ⇒ Boolean
Return true if the setting has a datetime value type.
484 485 486 |
# File 'lib/super_settings/setting.rb', line 484 def datetime? value_type == DATETIME end |
#delete! ⇒ void
This method returns an undefined value.
Mark the record as deleted. The record will not actually be deleted since it's still needed for caching purposes, but it will no longer be returned by queries.
542 543 544 |
# File 'lib/super_settings/setting.rb', line 542 def delete! update!(deleted: true) end |
#deleted=(val) ⇒ Object
Set the deleted flag on the setting. Deleted settings are not visible but are not actually removed from the data store.
418 419 420 421 422 |
# File 'lib/super_settings/setting.rb', line 418 def deleted=(val) val = Coerce.boolean(val) will_change!(:deleted, val) unless deleted? == val @record.deleted = val end |
#deleted? ⇒ Boolean Also known as: deleted
Return true if the setting has been marked as deleted.
408 409 410 |
# File 'lib/super_settings/setting.rb', line 408 def deleted? @record.deleted? end |
#description ⇒ String
Get the description for the setting.
391 392 393 |
# File 'lib/super_settings/setting.rb', line 391 def description @record.description end |
#description=(val) ⇒ Object
Set the description of the setting.
398 399 400 401 402 403 |
# File 'lib/super_settings/setting.rb', line 398 def description=(val) val = val&.to_s val = nil if val && val.empty? will_change!(:description, val) unless description == val @record.description = val end |
#float? ⇒ Boolean
Return true if the setting has a float value type.
472 473 474 |
# File 'lib/super_settings/setting.rb', line 472 def float? value_type == FLOAT end |
#history(limit: nil, offset: 0) ⇒ Array<SuperSettings::History>
Return array of history items reflecting changes made to the setting over time. Items should be returned in reverse chronological order so that the most recent changes are first.
559 560 561 |
# File 'lib/super_settings/setting.rb', line 559 def history(limit: nil, offset: 0) @record.history(limit: limit, offset: offset) end |
#integer? ⇒ Boolean
Return true if the setting has an integer value type.
466 467 468 |
# File 'lib/super_settings/setting.rb', line 466 def integer? value_type == INTEGER end |
#key ⇒ String
Get the unique key for the setting.
339 340 341 |
# File 'lib/super_settings/setting.rb', line 339 def key @record.key end |
#key=(val) ⇒ Object
Set the value of the setting. The value will be coerced to a string for storage.
346 347 348 349 350 |
# File 'lib/super_settings/setting.rb', line 346 def key=(val) val = val&.to_s will_change!(:key, val) unless key == val @record.key = val end |
#persisted? ⇒ Boolean
Return true if the record has been stored in the data storage engine.
521 522 523 |
# File 'lib/super_settings/setting.rb', line 521 def persisted? @record.persisted? end |
#save! ⇒ void
This method returns an undefined value.
Save the setting to the data storage engine.
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 |
# File 'lib/super_settings/setting.rb', line 497 def save! unless valid? raise InvalidRecordError.new(errors.values.join("; ")) end return if @changes.empty? = Time.now self.created_at ||= self.updated_at = if updated_at.nil? || !changed?(:updated_at) self.class.storage.with_connection do self.class.transaction do record_value_change @record.save! self.class.add_record_to_transaction(self) end end nil end |
#string? ⇒ Boolean
Return true if the setting has a string value type.
459 460 461 |
# File 'lib/super_settings/setting.rb', line 459 def string? value_type == STRING end |
#to_json(options = nil) ⇒ String
Serialize to a JSON string.
584 585 586 |
# File 'lib/super_settings/setting.rb', line 584 def to_json( = nil) as_json.to_json() end |
#update!(attributes) ⇒ void
This method returns an undefined value.
Update the setting attributes and save it.
550 551 552 553 |
# File 'lib/super_settings/setting.rb', line 550 def update!(attributes) self.attributes = attributes save! end |
#updated_at ⇒ Time
Get the time the setting was last updated.
443 444 445 |
# File 'lib/super_settings/setting.rb', line 443 def updated_at @record.updated_at end |
#updated_at=(val) ⇒ Object
Set the time when the setting was last updated.
450 451 452 453 454 |
# File 'lib/super_settings/setting.rb', line 450 def updated_at=(val) val = TimePrecision.new(val).time will_change!(:updated_at, val) unless updated_at == val @record.updated_at = val end |
#valid? ⇒ Boolean
Return true if the record has valid data.
528 529 530 531 |
# File 'lib/super_settings/setting.rb', line 528 def valid? validate! @errors.empty? end |
#value ⇒ Object
The value of a setting coerced to the appropriate class depending on its value type.
355 356 357 358 359 360 361 |
# File 'lib/super_settings/setting.rb', line 355 def value if deleted? nil else coerce(raw_value) end end |
#value=(val) ⇒ Object
Set the value of the setting.
366 367 368 369 370 |
# File 'lib/super_settings/setting.rb', line 366 def value=(val) val = serialize(val) unless val.is_a?(Array) val = val.join("\n") if val.is_a?(Array) self.raw_value = val end |
#value_changed? ⇒ Boolean
Return true if the value of the setting has changed. In addition to changing the value, this will be triggered if the key changed or if the setting was marked as deleted.
601 602 603 |
# File 'lib/super_settings/setting.rb', line 601 def value_changed? (@changes.keys & %w[key raw_value deleted]).any? end |
#value_type ⇒ String
Get the type of value being stored in the setting.
375 376 377 |
# File 'lib/super_settings/setting.rb', line 375 def value_type @record.value_type end |
#value_type=(val) ⇒ Object
Set the value type of the setting.
382 383 384 385 386 |
# File 'lib/super_settings/setting.rb', line 382 def value_type=(val) val = val&.to_s will_change!(:value_type, val) unless value_type == val @record.value_type = val end |