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 +4 -4
- data/README.md +54 -18
- data/lib/rails-settings/base.rb +54 -32
- data/lib/rails-settings/railtie.rb +1 -1
- data/lib/rails-settings/request_cache.rb +3 -3
- data/lib/rails-settings/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d45081eacc51de459cd0bc48469430474cd561386e924b40996bd5f66c1299e5
|
4
|
+
data.tar.gz: 485e2df525a6d3b66dfed0c0b5935aa8134b13ae0b0528d1fae536e5b19e4ae2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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) [![
|
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
|
-
|
43
|
-
|
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
|
-
|
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
|
data/lib/rails-settings/base.rb
CHANGED
@@ -1,14 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RailsSettings
|
4
|
-
class
|
5
|
-
|
4
|
+
class ProcetedKeyError < RuntimeError
|
5
|
+
def initialize(key)
|
6
|
+
super("Can't use #{key} as setting key.")
|
7
|
+
end
|
8
|
+
end
|
6
9
|
|
7
|
-
|
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,
|
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
|
-
|
44
|
-
|
45
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
119
|
+
record.save!
|
99
120
|
|
100
121
|
value
|
101
122
|
end
|
102
123
|
|
103
124
|
if validates
|
104
|
-
validates[:if] =
|
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
|
-
|
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
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
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
|
182
|
+
_all_settings[var_name]
|
159
183
|
end
|
160
184
|
|
161
185
|
def _table_exists?
|
162
186
|
table_exists?
|
163
|
-
rescue
|
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 ||=
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
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
|
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
|
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.
|
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:
|
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
|
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.
|
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: []
|