rails-settings-cached 2.2.0 → 2.3.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 765057576ddcdb19d9f394f1844950f03e8c70944abd9b104e70824f60f7e0e5
4
- data.tar.gz: 0d2a2c4aa7560d96bee3a0c1a0d50f7cb89bffd5c650ae47f2bd6169c0d12b6e
3
+ metadata.gz: '08fedca17d5c8848f9503a0b9a2d45403fd545406ec656d899af182334d6c3ac'
4
+ data.tar.gz: 1b928531e53c09d4ac3c582785aad54dee23f81c00721857009c0495ee1a7f30
5
5
  SHA512:
6
- metadata.gz: 908f7ae3d8e01710f9df4cb32a77b2302129107bcd34254cb5237fc5f5b98f2e4007fe315751ab3fd7e2212e14a0db133f796f994b0bd6a1cee48768717a01a9
7
- data.tar.gz: fe611e7af4ac5ca72a98040c63b0475833878ac6f11b82953fd80458bb6b96311fff7fc174f890171f466f724be809cd334bc184b0cb0c8c7b3ae94f5fbee28f
6
+ metadata.gz: 8f742e343ecfe97413a17aafefead8f5e49a49d407e269962a90e08a3f8ad89441f0ba95f4496a80b8528f68d5edecccf930f00af39627020d75a8e947ac28a5
7
+ data.tar.gz: 970ef16a4a2f2c3c552f0d80d8386d5124e3821c0f9ed54d2ad3b0dd57e3c37a7cf94a6342c14d4cb585a6e188c2659ba13034607768eb2dfd29680c5c084a5f
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ## Rails Settings Cached
1
+ # Rails Settings Cached
2
2
 
3
3
  This a plugin that makes managing a table of
4
4
  а global key, value pairs easy. Think of it like a global Hash stored in your database,
@@ -6,39 +6,23 @@ that uses simple ActiveRecord like methods for manipulation. Keep track of any g
6
6
  setting that you don't want to hard code into your rails app. You can store any kind
7
7
  of object. Strings, numbers, arrays, or any object.
8
8
 
9
- > 🚨 BREAK CHANGES WARNING:
10
- > rails-settings-cached 2.x has redesigned the API, the new version will compatible with the stored setting values by an older version.
11
- > When you want to upgrade 2.x, you must read the README again, and follow guides to change your Setting model.
12
- > 0.x stable branch: https://github.com/huacnlee/rails-settings-cached/tree/0.x
13
-
14
- ## Status
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)
15
10
 
16
- [![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) [![Code Climate](https://codeclimate.com/github/huacnlee/rails-settings-cached/badges/gpa.svg)](https://codeclimate.com/github/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)
17
-
18
- ## Setup
11
+ ## Installation
19
12
 
20
13
  Edit your Gemfile:
21
14
 
22
- ```ruby
23
- gem "rails-settings-cached", "~> 2.0"
24
- ```
25
-
26
- Generate your settings:
27
-
28
15
  ```bash
29
- $ rails g settings:install
16
+ $ bundle add rails-settings-cached
30
17
  ```
31
18
 
32
- If you want custom model name:
19
+ Generate your settings:
33
20
 
34
21
  ```bash
35
22
  $ rails g settings:install
36
- ```
37
23
 
38
- Or use a custom name:
39
-
40
- ```bash
41
- $ rails g settings:install SiteConfig
24
+ # Or use a custom name:
25
+ $ rails g settings:install AppConfig
42
26
  ```
43
27
 
44
28
  You will get `app/models/setting.rb`
@@ -46,20 +30,26 @@ You will get `app/models/setting.rb`
46
30
  ```rb
47
31
  class Setting < RailsSettings::Base
48
32
  # cache_prefix { "v1" }
49
-
50
- field :host, default: "http://example.com"
33
+ field :app_name, default: "Rails Settings"
34
+ field :host, default: "http://example.com", readonly: true
35
+ field :default_locale, default: "zh-CN"
51
36
  field :readonly_item, type: :integer, default: 100, readonly: true
52
37
  field :user_limits, type: :integer, default: 20
53
38
  field :exchange_rate, type: :float, default: 0.123
54
39
  field :admin_emails, type: :array, default: %w[admin@rubyonrails.org]
40
+ field :captcha_enable, type: :boolean, default: true
41
+
55
42
  # Override array separator, default: /[\n,]/ split with \n or comma.
56
43
  field :tips, type: :array, separator: /[\n]+/
57
- field :captcha_enable, type: :boolean, default: 1
44
+
58
45
  field :notification_options, type: :hash, default: {
59
46
  send_all: true,
60
47
  logging: true,
61
48
  sender_email: "foo@bar.com"
62
49
  }
50
+
51
+ # lambda default value
52
+ field :welcome_message, type: :string, default: -> { "welcome to #{self.app_name}" }
63
53
  end
64
54
  ```
65
55
 
@@ -68,19 +58,21 @@ You must use `field` method to statement the setting keys, otherwise you can't u
68
58
  Now just put that migration in the database with:
69
59
 
70
60
  ```bash
71
- rake db:migrate
61
+ $ rails db:migrate
72
62
  ```
73
63
 
74
64
  ## Usage
75
65
 
76
- The syntax is easy. First, let's create some settings to keep track of:
66
+ The syntax is easy. First, let's create some settings to keep track of:
77
67
 
78
68
  ```ruby
79
69
  irb > Setting.host
80
70
  "http://example.com"
81
- irb > Setting.host = "https://your-host.com"
82
- irb > Setting.host
83
- "https://your-host.com"
71
+ irb > Setting.app_name
72
+ "Rails Settings"
73
+ irb > Setting.app_name = "Rails Settings Cached"
74
+ irb > Setting.app_name
75
+ "Rails Settings Cached"
84
76
 
85
77
  irb > Setting.user_limits
86
78
  20
@@ -134,6 +126,31 @@ irb > Setting.notification_options
134
126
  }
135
127
  ```
136
128
 
129
+
130
+ ### Get defined fields
131
+
132
+ > version 2.3+
133
+
134
+ ```rb
135
+ # Get all keys
136
+ Setting.keys
137
+ => ["app_name", "host", "default_locale", "readonly_item"]
138
+
139
+ # Get editable keys
140
+ Settng.editable_keys
141
+ => ["app_name", "default_locale"]
142
+
143
+ # Get readonly keys
144
+ Setting.readonly_keys
145
+ => ["host", "readonly_item"]
146
+
147
+ # Get options of field
148
+ Setting.get_field("host")
149
+ => { key: "host", type: :string, default: "http://example.com", readonly: true }
150
+ Setting.get_field("app_name")
151
+ => { key: "app_name", type: :string, default: "Rails Settings", readonly: false }
152
+ ```
153
+
137
154
  ## Readonly field
138
155
 
139
156
  Sometimes you may need to use Setting before Rails is initialized, for example `config/devise.rb`
@@ -156,6 +173,26 @@ class Setting < RailsSettings::Base
156
173
  end
157
174
  ```
158
175
 
176
+ ## Use Setting in Rails initalizing:
177
+
178
+ You can't use Setting in these locations:
179
+
180
+ ```
181
+ config/application.rb
182
+ config/environments/*.rb
183
+ ```
184
+
185
+ If you wants do that, put the setting into `config/initializers/*.rb`
186
+
187
+ For example:
188
+
189
+ ```rb
190
+ # config/initializers/devise.rb
191
+ Devise.setup do |config|
192
+ config.omniauth :twitter, Setting.twitter_api_key, Setting.twitter_api_secret
193
+ end
194
+ ```
195
+
159
196
  ### Caching flow:
160
197
 
161
198
  ```
@@ -201,7 +238,7 @@ config/routes.rb
201
238
 
202
239
  ```rb
203
240
  namespace :admin do
204
- resources :settings
241
+ resource :settings
205
242
  end
206
243
  ```
207
244
 
@@ -257,78 +294,50 @@ app/views/admin/settings/show.html.erb
257
294
  Use YAML format to config the SMTP_html
258
295
  </div>
259
296
  </div>
260
- <% end %>
261
- ```
262
-
263
- ## Backward compatible to support 0.x scoped settings
264
-
265
- You may used the scoped setting feature in 0.x version. Before you upgrade rails-settings-cached 2.x, you must follow this guide to backward compatible it.
266
-
267
- For example:
268
297
 
269
- ```rb
270
- class User < ApplicationRecord
271
- include RailsSettings::Extend
272
- end
273
-
274
- @user.settings.color = "red"
275
- @user.settings.foo = 123
298
+ <div>
299
+ <%= f.submit 'Update Settings' %>
300
+ </div>
301
+ <% end %>
276
302
  ```
277
303
 
278
- create `app/models/concerns/scoped_setting.rb`
304
+ ## Scoped Settings
279
305
 
280
- ```rb
281
- module ScopedSetting
282
- extend ActiveSupport::Concern
306
+ > 🚨 BREAK CHANGES WARNING:
307
+ > rails-settings-cached 2.x has redesigned the API, the new version will compatible with the stored setting values by an older version.
308
+ > When you want to upgrade 2.x, you must read the README again, and follow guides to change your Setting model.
309
+ > 0.x stable branch: https://github.com/huacnlee/rails-settings-cached/tree/0.x
283
310
 
284
- included do
285
- has_many :settings, as: :thing
286
- end
311
+ - [Backward compatible to support 0.x scoped settings](docs/backward-compatible-to-scoped-settings.md)
287
312
 
288
- class_methods do
289
- def scoped_field(name, default: nil)
290
- define_method(name) do
291
- obj = settings.where(var: name).take || settings.new(var: name, value: default)
292
- obj.value
293
- end
313
+ For new project / new user of rails-settings-cached. The [ActiveRecord::AttributeMethods::Serialization](https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize) is best choice.
294
314
 
295
- define_method("#{name}=") do |val|
296
- record = settings.where(var: name).take || settings.new(var: name)
297
- record.value = val
298
- record.save!
315
+ > This is reason of why rails-settings-cached 2.x removed **Scoped Settings** feature.
299
316
 
300
- val
301
- end
302
- end
303
- end
304
- end
305
- ```
317
+ For example:
306
318
 
307
- Now include it for your model:
319
+ We wants a preferences setting for user.
308
320
 
309
321
  ```rb
310
- class User < ApplicationRecord
311
- include ScopedSetting
312
-
313
- scoped_field :color, default: ""
314
- scoped_field :foo, default: 0
322
+ class User < ActiveRecord::Base
323
+ serialize :preferences
315
324
  end
316
- ```
317
-
318
- Now you must to find project with ".setting." for replace with:
319
325
 
320
- Same values will fetch from the `settings` table.
321
-
322
- ```rb
323
- @user.color = "red"
324
- @user.color # => "red"
325
- @user.foo = 123
326
- @user.foo # =>
326
+ @user = User.new
327
+ @user.preferences[:receive_emails] = true
328
+ @user.preferences[:public_email] = true
329
+ @user.save
327
330
  ```
328
331
 
329
332
  ## Use cases:
330
333
 
331
- - [ruby-china/homeland](https://github.com/ruby-china/homeland)
332
- - [thebluedoc/bluedoc](https://github.com/thebluedoc/bluedoc/blob/master/app/models/setting.rb)
333
- - [tootsuite/mastodon](https://github.com/tootsuite/mastodon)
334
- - [helpyio/helpy](https://github.com/helpyio/helpy)
334
+ - [ruby-china/homeland](https://github.com/ruby-china/homeland) - master
335
+ - [forem/forem](https://github.com/forem/forem) - 2.x
336
+ - [siwapp/siwapp](https://github.com/siwapp/siwapp) - 2.x
337
+ - [aidewoode/black_candy](https://github.com/aidewoode/black_candy) - 2.x
338
+ - [thebluedoc/bluedoc](https://github.com/thebluedoc/bluedoc/blob/master/app/models/setting.rb) - 2.x
339
+ - [tootsuite/mastodon](https://github.com/tootsuite/mastodon) - 0.6.x
340
+ - [helpyio/helpy](https://github.com/helpyio/helpy) - 0.5.x
341
+
342
+
343
+ And more than [1K repositories](https://github.com/huacnlee/rails-settings-cached/network/dependents) used.
@@ -3,14 +3,15 @@
3
3
  require "rails/generators"
4
4
  require "rails/generators/migration"
5
5
 
6
- module Settings
6
+ module RailsSettings
7
7
  class InstallGenerator < Rails::Generators::NamedBase
8
+ namespace "settings:install"
8
9
  desc "Generate RailsSettings files."
9
10
  include Rails::Generators::Migration
10
11
 
11
12
  argument :name, type: :string, default: "setting"
12
13
 
13
- source_root File.expand_path("../templates", __FILE__)
14
+ source_root File.expand_path("templates", __dir__)
14
15
 
15
16
  @@migrations = false
16
17
 
@@ -6,7 +6,7 @@ module RailsSettings
6
6
  class Base < ActiveRecord::Base
7
7
  class SettingNotFound < RuntimeError; end
8
8
 
9
- SEPARATOR_REGEXP = /[\n,;]+/
9
+ SEPARATOR_REGEXP = /[\n,;]+/.freeze
10
10
  self.table_name = table_name_prefix + "settings"
11
11
 
12
12
  # get the value field, YAML decoded
@@ -26,15 +26,17 @@ module RailsSettings
26
26
  class << self
27
27
  def clear_cache
28
28
  RequestStore.store[:rails_settings_all_settings] = nil
29
- Rails.cache.delete(self.cache_key)
29
+ Rails.cache.delete(cache_key)
30
30
  end
31
31
 
32
32
  def field(key, **opts)
33
- @keys ||= []
34
- @keys << key.to_s
35
33
  _define_field(key, default: opts[:default], type: opts[:type], readonly: opts[:readonly], separator: opts[:separator])
36
34
  end
37
35
 
36
+ def get_field(key)
37
+ @defined_fields.find { |field| field[:key] == key.to_s } || {}
38
+ end
39
+
38
40
  def cache_prefix(&block)
39
41
  @cache_prefix = block
40
42
  end
@@ -46,96 +48,130 @@ module RailsSettings
46
48
  end
47
49
 
48
50
  def keys
49
- @keys
51
+ @defined_fields.map { |field| field[:key] }
52
+ end
53
+
54
+ def editable_keys
55
+ @defined_fields.reject { |field| field[:readonly] }.map { |field| field[:key] }
56
+ end
57
+
58
+ def readonly_keys
59
+ @defined_fields.select { |field| field[:readonly] }.map { |field| field[:key] }
50
60
  end
51
61
 
52
62
  private
53
63
 
54
- def _define_field(key, default: nil, type: :string, readonly: false, separator: nil)
55
- if readonly
56
- define_singleton_method(key) do
57
- self.send(:_convert_string_to_typeof_value, type, default, separator: separator)
58
- end
59
- else
60
- define_singleton_method(key) do
61
- val = self.send(:_value_of, key)
62
- result = nil
63
- if !val.nil?
64
- result = val
65
- else
66
- result = default
67
- result = default.call if default.is_a?(Proc)
68
- end
69
-
70
- result = self.send(:_convert_string_to_typeof_value, type, result, separator: separator)
71
-
72
- result
64
+ def _define_field(key, default: nil, type: :string, readonly: false, separator: nil)
65
+ @defined_fields ||= []
66
+ @defined_fields << {
67
+ key: key.to_s,
68
+ default: default,
69
+ type: type || :string,
70
+ readonly: readonly.nil? ? false : readonly
71
+ }
72
+
73
+ if readonly
74
+ define_singleton_method(key) do
75
+ send(:_convert_string_to_typeof_value, type, default, separator: separator)
76
+ end
77
+ else
78
+ define_singleton_method(key) do
79
+ val = send(:_value_of, key)
80
+ result = nil
81
+ if !val.nil?
82
+ result = val
83
+ else
84
+ result = default
85
+ result = default.call if default.is_a?(Proc)
73
86
  end
74
87
 
75
- define_singleton_method("#{key}=") do |value|
76
- var_name = key.to_s
88
+ result = send(:_convert_string_to_typeof_value, type, result, separator: separator)
77
89
 
78
- record = find_by(var: var_name) || new(var: var_name)
79
- value = self.send(:_convert_string_to_typeof_value, type, value, separator: separator)
90
+ result
91
+ end
80
92
 
81
- record.value = value
82
- record.save!
93
+ define_singleton_method("#{key}=") do |value|
94
+ var_name = key.to_s
83
95
 
84
- value
85
- end
86
- end
96
+ record = find_by(var: var_name) || new(var: var_name)
97
+ value = send(:_convert_string_to_typeof_value, type, value, separator: separator)
87
98
 
88
- if type == :boolean
89
- define_singleton_method("#{key}?") do
90
- self.send(key)
91
- end
99
+ record.value = value
100
+ record.save!
101
+
102
+ value
92
103
  end
93
104
  end
94
105
 
95
- def _convert_string_to_typeof_value(type, value, separator: nil)
96
- return value unless [String, Integer, Float, BigDecimal].include?(value.class)
97
-
98
- case type
99
- when :boolean
100
- value == "true" || value == "1" || value == 1 || value == true
101
- when :array
102
- value.split(separator || SEPARATOR_REGEXP).reject { |str| str.empty? }.map(&:strip)
103
- when :hash
104
- value = YAML.load(value).to_h rescue eval(value).to_h rescue {}
105
- value.deep_stringify_keys!
106
- value
107
- when :integer
108
- value.to_i
109
- when :float
110
- value.to_f
111
- when :big_decimal
112
- value.to_d
113
- else
114
- value
106
+ if type == :boolean
107
+ define_singleton_method("#{key}?") do
108
+ send(key)
115
109
  end
116
110
  end
111
+ end
117
112
 
118
- def _value_of(var_name)
119
- raise "#{self.table_name} does not exist." unless table_exists?
113
+ def _convert_string_to_typeof_value(type, value, separator: nil)
114
+ return value unless [String, Integer, Float, BigDecimal].include?(value.class)
115
+
116
+ case type
117
+ when :boolean
118
+ value == "true" || value == "1" || value == 1 || value == true
119
+ when :array
120
+ value.split(separator || SEPARATOR_REGEXP).reject { |str| str.empty? }.map(&:strip)
121
+ when :hash
122
+ value = begin
123
+ begin
124
+ YAML.load(value).to_h
125
+ rescue StandardError
126
+ eval(value).to_h
127
+ end
128
+ rescue StandardError
129
+ {}
130
+ end
131
+ value.deep_stringify_keys!
132
+ ActiveSupport::HashWithIndifferentAccess.new(value)
133
+ when :integer
134
+ value.to_i
135
+ when :float
136
+ value.to_f
137
+ when :big_decimal
138
+ value.to_d
139
+ else
140
+ value
141
+ end
142
+ end
120
143
 
121
- _all_settings[var_name.to_s]
144
+ def _value_of(var_name)
145
+ unless table_exists?
146
+ # Fallback to default value if table was not ready (before migrate)
147
+ puts "WARNING: table: \"#{table_name}\" does not exist, `#{name}.#{var_name}` fallback to returns the default value."
148
+ return nil
122
149
  end
123
150
 
124
- def rails_initialized?
125
- Rails.application && Rails.application.initialized?
151
+ _all_settings[var_name.to_s]
152
+ rescue => e
153
+ if e.message.include?("connect")
154
+ puts "WARNING: `#{name}.#{var_name}` called but no connection, fallback to returns the default value."
155
+ return nil
126
156
  end
127
157
 
128
- def _all_settings
129
- raise "You cannot use settings before Rails initialize." unless rails_initialized?
130
- RequestStore.store[:rails_settings_all_settings] ||= begin
131
- Rails.cache.fetch(self.cache_key, expires_in: 1.week) do
132
- vars = unscoped.select("var, value")
133
- result = {}
134
- vars.each { |record| result[record.var] = record.value }
135
- result.with_indifferent_access
136
- end
158
+ raise e
159
+ end
160
+
161
+ def rails_initialized?
162
+ Rails.application&.initialized?
163
+ end
164
+
165
+ def _all_settings
166
+ RequestStore.store[:rails_settings_all_settings] ||= begin
167
+ Rails.cache.fetch(cache_key, expires_in: 1.week) do
168
+ vars = unscoped.select("var, value")
169
+ result = {}
170
+ vars.each { |record| result[record.var] = record.value }
171
+ result.with_indifferent_access
137
172
  end
138
173
  end
174
+ end
139
175
  end
140
176
  end
141
177
  end
@@ -3,7 +3,7 @@
3
3
  module RailsSettings
4
4
  class << self
5
5
  def version
6
- "2.2.0"
6
+ "2.3.4"
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.2.0
4
+ version: 2.3.4
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-06-29 00:00:00.000000000 Z
11
+ date: 2020-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -130,9 +130,10 @@ files:
130
130
  - lib/rails-settings/railtie.rb
131
131
  - lib/rails-settings/version.rb
132
132
  homepage: https://github.com/huacnlee/rails-settings-cached
133
- licenses: []
133
+ licenses:
134
+ - MIT
134
135
  metadata: {}
135
- post_install_message:
136
+ post_install_message:
136
137
  rdoc_options: []
137
138
  require_paths:
138
139
  - lib
@@ -148,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
149
  version: '0'
149
150
  requirements: []
150
151
  rubygems_version: 3.0.3
151
- signing_key:
152
+ signing_key:
152
153
  specification_version: 4
153
154
  summary: Settings plugin for Rails that makes managing a table of global keys.
154
155
  test_files: []