rails-settings-cached 2.5.0 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f37f8d9bad4b40dd60dbf30806e1e530e1d292448ba803db06bdcca5f562c62e
4
- data.tar.gz: 2900b13077db46b60b2c22cfa3a21b7af5704b86d874d485672508c8ef866475
3
+ metadata.gz: d45081eacc51de459cd0bc48469430474cd561386e924b40996bd5f66c1299e5
4
+ data.tar.gz: 485e2df525a6d3b66dfed0c0b5935aa8134b13ae0b0528d1fae536e5b19e4ae2
5
5
  SHA512:
6
- metadata.gz: c696568044b97ce9a9112de42682a7e484e13a8220e0d7b1b52d5977f56358f82109e4bb1dd8b227f89089d060a49454b2bd1c86ac4cc7fbfc2c275bf0a48c55
7
- data.tar.gz: c2eb40491e08ce8eefe6d96e6d987fd9a02efbad708e9a1ae0442d98b82e626300ee90eda5664be385aa81178c4be4a19b190d623a2ff8cdb0d8e0f8b53d0649
6
+ metadata.gz: 6651da35fec5737f76192ec01f0980ea45a85c69efb768c22edbce29b490f29dfa2498798b5af6d45a126955a3fe72bf2fa1ae76bd249237b83f408f7bba72c4
7
+ data.tar.gz: b96670e501b9c5aff237b02fd2da2560b654dd2835322b2e64e28679e3edf646ee940f2f2ffe69bfa7d851732ac4844bb47b01e292f4ef4b5f04e587977f8c21
data/README.md CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  The best solution for store global settings in Rails applications.
4
4
 
5
- This gem will managing a table of а global key, value pairs easy. Think of it like a global Hash stored in your database, that uses simple ActiveRecord like methods for manipulation. Keep track of any global setting that you don't want to hard code into your rails app.
5
+ This gem will make managing a table of а global key, value pairs easy. Think of it like a global Hash stored in your database, that uses simple ActiveRecord like methods for manipulation. Keep track of any global setting that you don't want to hard code into your rails app.
6
6
 
7
7
  You can store any kind of object. Strings, numbers, arrays, booleans, or any object.
8
8
 
9
- [![Gem Version](https://badge.fury.io/rb/rails-settings-cached.svg)](https://rubygems.org/gems/rails-settings-cached) [![CI Status](https://travis-ci.org/huacnlee/rails-settings-cached.svg)](http://travis-ci.org/huacnlee/rails-settings-cached) [![codecov.io](https://codecov.io/github/huacnlee/rails-settings-cached/coverage.svg?branch=master)](https://codecov.io/github/huacnlee/rails-settings-cached?branch=master)
9
+ [![Gem Version](https://badge.fury.io/rb/rails-settings-cached.svg)](https://rubygems.org/gems/rails-settings-cached) [![build](https://github.com/huacnlee/rails-settings-cached/workflows/build/badge.svg)](https://github.com/huacnlee/rails-settings-cached/actions?query=workflow%3Abuild) [![codecov.io](https://codecov.io/github/huacnlee/rails-settings-cached/coverage.svg?branch=master)](https://codecov.io/github/huacnlee/rails-settings-cached?branch=master)
10
10
 
11
11
  ## Installation
12
12
 
@@ -30,26 +30,32 @@ You will get `app/models/setting.rb`
30
30
  ```rb
31
31
  class Setting < RailsSettings::Base
32
32
  # cache_prefix { "v1" }
33
- field :app_name, default: "Rails Settings", validates: { presence: true, length: { in: 2..20 } }
34
- field :host, default: "http://example.com", readonly: true
35
- field :default_locale, default: "zh-CN", validates: { presence: true, inclusion: { in: %w[zh-CN en jp] } }
36
- field :readonly_item, type: :integer, default: 100, readonly: true
37
- field :user_limits, type: :integer, default: 20
38
- field :exchange_rate, type: :float, default: 0.123
39
- field :admin_emails, type: :array, default: %w[admin@rubyonrails.org]
40
- field :captcha_enable, type: :boolean, default: true
41
33
 
42
- # Override array separator, default: /[\n,]/ split with \n or comma.
43
- field :tips, type: :array, separator: /[\n]+/
34
+ scope :application do
35
+ field :app_name, default: "Rails Settings", validates: { presence: true, length: { in: 2..20 } }
36
+ field :host, default: "http://example.com", readonly: true
37
+ field :default_locale, default: "zh-CN", validates: { presence: true, inclusion: { in: %w[zh-CN en jp] } }, option_values: %w[en zh-CN]
38
+ field :admin_emails, type: :array, default: %w[admin@rubyonrails.org]
39
+
40
+ # lambda default value
41
+ field :welcome_message, type: :string, default: -> { "welcome to #{self.app_name}" }, validates: { length: { maximum: 255 } }
42
+ # Override array separator, default: /[\n,]/ split with \n or comma.
43
+ field :tips, type: :array, separator: /[\n]+/
44
+ end
45
+
46
+ scope :limits do
47
+ field :user_limits, type: :integer, default: 20
48
+ field :exchange_rate, type: :float, default: 0.123
49
+ field :captcha_enable, type: :boolean, default: true, group: :limits
50
+ end
44
51
 
45
52
  field :notification_options, type: :hash, default: {
46
53
  send_all: true,
47
54
  logging: true,
48
55
  sender_email: "foo@bar.com"
49
- }
56
+ }, group: :advanced
50
57
 
51
- # lambda default value
52
- field :welcome_message, type: :string, default: -> { "welcome to #{self.app_name}" }, validates: { length: { maximum: 255 } }
58
+ field :readonly_item, type: :integer, default: 100, readonly: true
53
59
  end
54
60
  ```
55
61
 
@@ -145,9 +151,24 @@ Setting.readonly_keys
145
151
 
146
152
  # Get options of field
147
153
  Setting.get_field("host")
148
- => { key: "host", type: :string, default: "http://example.com", readonly: true }
154
+ => { scope: :application, key: "host", type: :string, default: "http://example.com", readonly: true }
149
155
  Setting.get_field("app_name")
150
- => { key: "app_name", type: :string, default: "Rails Settings", readonly: false }
156
+ => { scope: :application, key: "app_name", type: :string, default: "Rails Settings", readonly: false }
157
+ Setting.get_field(:user_limits)
158
+ => { scope: :limits, key: "user_limits", type: :integer, default: 20, readonly: false }
159
+ ```
160
+
161
+ #### Get All defined fields
162
+
163
+ > version 2.7.0+
164
+
165
+ You can use `defined_fields` method to get all defined fields in Setting.
166
+
167
+ ```rb
168
+ # Get editable fields and group by scope
169
+ editable_fields = Setting.defined_fields
170
+ .select { |field| !field[:readonly] }
171
+ .group_by { |field| field[:scope] }
151
172
  ```
152
173
 
153
174
  ## Validations
@@ -162,9 +183,23 @@ class Setting < RailsSettings::Base
162
183
  end
163
184
  ```
164
185
 
165
- Now validate will work on record save.
186
+ Now validate will work on record save:
187
+
188
+ ```rb
189
+ irb> Setting.app_name = ""
190
+ ActiveRecord::RecordInvalid: (Validation failed: App name can't be blank)
191
+ irb> Setting.app_name = "Rails Settings"
192
+ "Rails Settings"
193
+ irb> Setting.default_locale = "zh-TW"
194
+ ActiveRecord::RecordInvalid: (Validation failed: Default locale is not included in [zh-CN, en, jp])
195
+ irb> Setting.default_locale = "en"
196
+ "en"
197
+ ```
198
+
199
+ Validate by `save` / `valid?` method:
166
200
 
167
201
  ```rb
202
+
168
203
  setting = Setting.find_or_initialize_by(var: :app_name)
169
204
  setting.value = ""
170
205
  setting.valid?
@@ -411,6 +446,7 @@ end
411
446
  - [huacnlee/bluedoc](https://github.com/huacnlee/bluedoc) - 2.x
412
447
  - [getzealot/zealot](https://github.com/getzealot/zealot) - 2.x
413
448
  - [kaishuu0123/rebacklogs](https://github.com/kaishuu0123/rebacklogs) - 2.x
449
+ - [texterify/texterify](https://github.com/texterify/texterify) - 2.x
414
450
  - [tootsuite/mastodon](https://github.com/tootsuite/mastodon) - 0.6.x
415
451
  - [helpyio/helpy](https://github.com/helpyio/helpy) - 0.5.x
416
452
  - [daqing/rabel](https://github.com/daqing/rabel) - 0.4.x
@@ -1,14 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsSettings
4
- class Base < ActiveRecord::Base
5
- class SettingNotFound < RuntimeError; end
4
+ class ProcetedKeyError < RuntimeError
5
+ def initialize(key)
6
+ super("Can't use #{key} as setting key.")
7
+ end
8
+ end
6
9
 
7
- SEPARATOR_REGEXP = /[\n,;]+/.freeze
10
+ class Base < ActiveRecord::Base
11
+ SEPARATOR_REGEXP = /[\n,;]+/
12
+ PROTECTED_KEYS = %w[var value]
8
13
  self.table_name = table_name_prefix + "settings"
9
14
 
10
15
  # get the value field, YAML decoded
11
16
  def value
17
+ # rubocop:disable Security/YAMLLoad
12
18
  YAML.load(self[:value]) if self[:value].present?
13
19
  end
14
20
 
@@ -28,7 +34,13 @@ module RailsSettings
28
34
  end
29
35
 
30
36
  def field(key, **opts)
31
- _define_field(key, default: opts[:default], type: opts[:type], readonly: opts[:readonly], separator: opts[:separator], validates: opts[:validates])
37
+ _define_field(key, **opts)
38
+ end
39
+
40
+ def scope(name)
41
+ @scope = name.to_sym
42
+ yield
43
+ @scope = nil
32
44
  end
33
45
 
34
46
  def get_field(key)
@@ -40,9 +52,9 @@ module RailsSettings
40
52
  end
41
53
 
42
54
  def cache_key
43
- scope = ["rails-settings-cached"]
44
- scope << @cache_prefix.call if @cache_prefix
45
- scope.join("/")
55
+ key_parts = ["rails-settings-cached"]
56
+ key_parts << @cache_prefix.call if @cache_prefix
57
+ key_parts.join("/")
46
58
  end
47
59
 
48
60
  def keys
@@ -57,20 +69,29 @@ module RailsSettings
57
69
  @defined_fields.select { |field| field[:readonly] }.map { |field| field[:key] }
58
70
  end
59
71
 
72
+ attr_reader :defined_fields
73
+
60
74
  private
61
75
 
62
- def _define_field(key, default: nil, type: :string, readonly: false, separator: nil, validates: nil)
76
+ def _define_field(key, default: nil, type: :string, readonly: false, separator: nil, validates: nil, **opts)
77
+ key = key.to_s
78
+
79
+ raise ProcetedKeyError.new(key) if PROTECTED_KEYS.include?(key)
80
+
63
81
  @defined_fields ||= []
64
82
  @defined_fields << {
65
- key: key.to_s,
83
+ scope: @scope,
84
+ key: key,
66
85
  default: default,
67
86
  type: type || :string,
68
- readonly: readonly.nil? ? false : readonly
87
+ readonly: readonly.nil? ? false : readonly,
88
+ options: opts
69
89
  }
70
90
 
71
91
  if readonly
72
92
  define_singleton_method(key) do
73
- send(:_convert_string_to_typeof_value, type, default, separator: separator)
93
+ result = default.is_a?(Proc) ? default.call : default
94
+ send(:_convert_string_to_typeof_value, type, result, separator: separator)
74
95
  end
75
96
  else
76
97
  define_singleton_method(key) do
@@ -89,19 +110,19 @@ module RailsSettings
89
110
  end
90
111
 
91
112
  define_singleton_method("#{key}=") do |value|
92
- var_name = key.to_s
113
+ var_name = key
93
114
 
94
115
  record = find_by(var: var_name) || new(var: var_name)
95
116
  value = send(:_convert_string_to_typeof_value, type, value, separator: separator)
96
117
 
97
118
  record.value = value
98
- record.save(validate: false)
119
+ record.save!
99
120
 
100
121
  value
101
122
  end
102
123
 
103
124
  if validates
104
- validates[:if] = Proc.new { |item| item.var.to_s == key.to_s }
125
+ validates[:if] = proc { |item| item.var.to_s == key }
105
126
  send(:validates, key, **validates)
106
127
 
107
128
  define_method(:read_attribute_for_validation) do |_key|
@@ -115,6 +136,13 @@ module RailsSettings
115
136
  send(key)
116
137
  end
117
138
  end
139
+
140
+ # delegate instance get method to class for support:
141
+ # setting = Setting.new
142
+ # setting.admin_emails
143
+ define_method(key) do
144
+ self.class.public_send(key)
145
+ end
118
146
  end
119
147
 
120
148
  def _convert_string_to_typeof_value(type, value, separator: nil)
@@ -122,19 +150,15 @@ module RailsSettings
122
150
 
123
151
  case type
124
152
  when :boolean
125
- value == "true" || value == "1" || value == 1 || value == true
153
+ ["true", "1", 1, true].include?(value)
126
154
  when :array
127
155
  value.split(separator || SEPARATOR_REGEXP).reject { |str| str.empty? }.map(&:strip)
128
156
  when :hash
129
157
  value = begin
130
- begin
131
- YAML.load(value).to_h
132
- rescue StandardError
133
- eval(value).to_h
134
- end
135
- rescue StandardError
136
- {}
137
- end
158
+ YAML.safe_load(value).to_h
159
+ rescue
160
+ {}
161
+ end
138
162
  value.deep_stringify_keys!
139
163
  ActiveSupport::HashWithIndifferentAccess.new(value)
140
164
  when :integer
@@ -155,12 +179,12 @@ module RailsSettings
155
179
  return nil
156
180
  end
157
181
 
158
- _all_settings[var_name.to_s]
182
+ _all_settings[var_name]
159
183
  end
160
184
 
161
185
  def _table_exists?
162
186
  table_exists?
163
- rescue => e
187
+ rescue
164
188
  false
165
189
  end
166
190
 
@@ -169,13 +193,11 @@ module RailsSettings
169
193
  end
170
194
 
171
195
  def _all_settings
172
- RequestCache.settings ||= begin
173
- Rails.cache.fetch(cache_key, expires_in: 1.week) do
174
- vars = unscoped.select("var, value")
175
- result = {}
176
- vars.each { |record| result[record.var] = record.value }
177
- result.with_indifferent_access
178
- end
196
+ RequestCache.settings ||= Rails.cache.fetch(cache_key, expires_in: 1.week) do
197
+ vars = unscoped.select("var, value")
198
+ result = {}
199
+ vars.each { |record| result[record.var] = record.value }
200
+ result.with_indifferent_access
179
201
  end
180
202
  end
181
203
  end
@@ -3,7 +3,7 @@
3
3
  module RailsSettings
4
4
  class Railtie < Rails::Railtie
5
5
  initializer "rails_settings.active_record.initialization" do
6
- RailsSettings::Base.after_commit :clear_cache, on: %i(create update destroy)
6
+ RailsSettings::Base.after_commit :clear_cache, on: %i[create update destroy]
7
7
  end
8
8
  end
9
9
  end
@@ -1,9 +1,9 @@
1
1
  module RailsSettings
2
- if defined? ActiveSupport::CurrentAttributes
2
+ if defined? ActiveSupport::CurrentAttributes
3
3
  # For storage all settings in Current, it will reset after per request completed.
4
4
  # Base on ActiveSupport::CurrentAttributes
5
5
  # https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html
6
- class RequestCache < ActiveSupport::CurrentAttributes
6
+ class RequestCache < ActiveSupport::CurrentAttributes
7
7
  attribute :settings
8
8
  end
9
9
  else
@@ -27,4 +27,4 @@ module RailsSettings
27
27
  end
28
28
  end
29
29
  end
30
- end
30
+ end
@@ -3,7 +3,7 @@
3
3
  module RailsSettings
4
4
  class << self
5
5
  def version
6
- "2.5.0"
6
+ "2.7.0"
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-settings-cached
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Lee
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-08 00:00:00.000000000 Z
11
+ date: 2021-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -110,7 +110,7 @@ dependencies:
110
110
  version: '0'
111
111
  description: "\n The best solution for store global settings in Rails applications.\n\n
112
112
  \ This gem will managing a table of а global key, value pairs easy. Think of it
113
- like a \n global Hash stored in your database, that uses simple ActiveRecord like
113
+ like a\n global Hash stored in your database, that uses simple ActiveRecord like
114
114
  methods for manipulation.\n\n Keep track of any global setting that you dont want
115
115
  to hard code into your rails app.\n You can store any kind of object. Strings,
116
116
  numbers, arrays, or any object.\n "
@@ -134,7 +134,7 @@ homepage: https://github.com/huacnlee/rails-settings-cached
134
134
  licenses:
135
135
  - MIT
136
136
  metadata: {}
137
- post_install_message:
137
+ post_install_message:
138
138
  rdoc_options: []
139
139
  require_paths:
140
140
  - lib
@@ -149,8 +149,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
149
  - !ruby/object:Gem::Version
150
150
  version: '0'
151
151
  requirements: []
152
- rubygems_version: 3.0.8
153
- signing_key:
152
+ rubygems_version: 3.2.3
153
+ signing_key:
154
154
  specification_version: 4
155
155
  summary: The best solution for store global settings in Rails applications.
156
156
  test_files: []