rails-settings-cached 2.2.0 → 2.3.4

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: 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: []