rails-settings-cached 2.4.1 → 2.6.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: 11dbf6161605ff3aed324a9ac29600d47918cd5fad1b8a5abfadaeddd9636c57
4
- data.tar.gz: 8056da8c1b7441dd6fc78117013b06c0d67b53bfb06497d1e2343b1417503b95
3
+ metadata.gz: 659ee746f1a087bb3ee48bba9f72a3dfd6af920830c6b003fd3bd909dce0a3c9
4
+ data.tar.gz: bb07a004ae0bbe413df58a0e2fd72fa7940cf5c55661c30214161745ebc5accc
5
5
  SHA512:
6
- metadata.gz: 61579ae6068bdd643c4741ac07855c0802220f11be06709910efae5f653dc69db7d7b039cb265bc4229a5121aef90ee9de92d6da700aea87cec33bfb9c4800f3
7
- data.tar.gz: 2fbd8d62d15ac420abc0ac96ca2aea53eb6d78c9072a1f19fa942f86fd89a8253e829ec827251909dc2cd8f2082e65e890737ba7588d4cf960ebad85fdc76269
6
+ metadata.gz: 2cbd53148b2110e12e8280a34691e9c08fb1e0805d2cc3ce8a4d25bbb477339e0116d508bac3bfb988bd96ffd3c173838475b5c85bb4659644b275585870198f
7
+ data.tar.gz: afe704c8920d76f70795ad55ac17a5ccbfa9807abe9903090fa797b1eb9a7ac4c5564b0a817ccca329b57704eebd3d688ad347c1f6afce58b4fbb58e20a029a1
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,9 +30,9 @@ 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"
33
+ field :app_name, default: "Rails Settings", validates: { presence: true, length: { in: 2..20 } }
34
34
  field :host, default: "http://example.com", readonly: true
35
- field :default_locale, default: "zh-CN"
35
+ field :default_locale, default: "zh-CN", validates: { presence: true, inclusion: { in: %w[zh-CN en jp] } }
36
36
  field :readonly_item, type: :integer, default: 100, readonly: true
37
37
  field :user_limits, type: :integer, default: 20
38
38
  field :exchange_rate, type: :float, default: 0.123
@@ -49,7 +49,7 @@ class Setting < RailsSettings::Base
49
49
  }
50
50
 
51
51
  # lambda default value
52
- field :welcome_message, type: :string, default: -> { "welcome to #{self.app_name}" }
52
+ field :welcome_message, type: :string, default: -> { "welcome to #{self.app_name}" }, validates: { length: { maximum: 255 } }
53
53
  end
54
54
  ```
55
55
 
@@ -150,6 +150,53 @@ Setting.get_field("app_name")
150
150
  => { key: "app_name", type: :string, default: "Rails Settings", readonly: false }
151
151
  ```
152
152
 
153
+ ## Validations
154
+
155
+ You can use `validates` options to special the [Rails Validation](https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates) for fields.
156
+
157
+ ```rb
158
+ class Setting < RailsSettings::Base
159
+ # cache_prefix { "v1" }
160
+ field :app_name, default: "Rails Settings", validates: { presence: true, length: { in: 2..20 } }
161
+ field :default_locale, default: "zh-CN", validates: { presence: true, inclusion: { in: %w[zh-CN en jp], message: "is not included in [zh-CN, en, jp]" } }
162
+ end
163
+ ```
164
+
165
+ Now validate will work on record save:
166
+
167
+ ```rb
168
+ irb> Setting.app_name = ""
169
+ ActiveRecord::RecordInvalid: (Validation failed: App name can't be blank)
170
+ irb> Setting.app_name = "Rails Settings"
171
+ "Rails Settings"
172
+ irb> Setting.default_locale = "zh-TW"
173
+ ActiveRecord::RecordInvalid: (Validation failed: Default locale is not included in [zh-CN, en, jp])
174
+ irb> Setting.default_locale = "en"
175
+ "en"
176
+ ```
177
+
178
+ Validate by `save` / `valid?` method:
179
+
180
+ ```rb
181
+
182
+ setting = Setting.find_or_initialize_by(var: :app_name)
183
+ setting.value = ""
184
+ setting.valid?
185
+ # => false
186
+ setting.errors.full_messages
187
+ # => ["App name can't be blank", "App name too short (minimum is 2 characters)"]
188
+
189
+ setting = Setting.find_or_initialize_by(var: :default_locale)
190
+ setting.value = "zh-TW"
191
+ setting.save
192
+ # => false
193
+ setting.errors.full_messages
194
+ # => ["Default locale is not included in [zh-CN, en, jp]"]
195
+ setting.value = "en"
196
+ setting.valid?
197
+ # => true
198
+ ```
199
+
153
200
  ## Use Setting in Rails initializing:
154
201
 
155
202
  In `version 2.3+` you can use Setting before Rails is initialized.
@@ -265,9 +312,25 @@ app/controllers/admin/settings_controller.rb
265
312
  module Admin
266
313
  class SettingsController < ApplicationController
267
314
  def create
315
+ @errors = ActiveModel::Errors.new
316
+ setting_params.keys.each do |key|
317
+ next if setting_params[key].nil?
318
+
319
+ setting = Setting.new(var: key)
320
+ setting.value = setting_params[key].strip
321
+ unless setting.valid?
322
+ @errors.merge!(setting.errors)
323
+ end
324
+ end
325
+
326
+ if @errors.any?
327
+ render :new
328
+ end
329
+
268
330
  setting_params.keys.each do |key|
269
331
  Setting.send("#{key}=", setting_params[key].strip) unless setting_params[key].nil?
270
332
  end
333
+
271
334
  redirect_to admin_settings_path, notice: "Setting was successfully updated."
272
335
  end
273
336
 
@@ -284,6 +347,16 @@ app/views/admin/settings/show.html.erb
284
347
 
285
348
  ```erb
286
349
  <%= form_for(Setting.new, url: admin_settings_path) do |f| %>
350
+ <% if @errors.any? %>
351
+ <div class="alert alert-block alert-danger">
352
+ <ul>
353
+ <% @errors.full_messages.each do |msg| %>
354
+ <li><%= msg %></li>
355
+ <% end %>
356
+ </ul>
357
+ </div>
358
+ <% end %>
359
+
287
360
  <div class="form-group">
288
361
  <label class="control-label">Host</label>
289
362
  <%= f.text_field :host, value: Setting.host, class: "form-control", placeholder: "http://localhost" %>
@@ -352,6 +425,7 @@ end
352
425
  - [huacnlee/bluedoc](https://github.com/huacnlee/bluedoc) - 2.x
353
426
  - [getzealot/zealot](https://github.com/getzealot/zealot) - 2.x
354
427
  - [kaishuu0123/rebacklogs](https://github.com/kaishuu0123/rebacklogs) - 2.x
428
+ - [texterify/texterify](https://github.com/texterify/texterify) - 2.x
355
429
  - [tootsuite/mastodon](https://github.com/tootsuite/mastodon) - 0.6.x
356
430
  - [helpyio/helpy](https://github.com/helpyio/helpy) - 0.5.x
357
431
  - [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,8 @@ 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])
37
+ _define_field(key, default: opts[:default], type: opts[:type], readonly: opts[:readonly],
38
+ separator: opts[:separator], validates: opts[:validates])
32
39
  end
33
40
 
34
41
  def get_field(key)
@@ -59,10 +66,14 @@ module RailsSettings
59
66
 
60
67
  private
61
68
 
62
- def _define_field(key, default: nil, type: :string, readonly: false, separator: nil)
69
+ def _define_field(key, default: nil, type: :string, readonly: false, separator: nil, validates: nil)
70
+ key = key.to_s
71
+
72
+ raise ProcetedKeyError.new(key) if PROTECTED_KEYS.include?(key)
73
+
63
74
  @defined_fields ||= []
64
75
  @defined_fields << {
65
- key: key.to_s,
76
+ key: key,
66
77
  default: default,
67
78
  type: type || :string,
68
79
  readonly: readonly.nil? ? false : readonly
@@ -70,7 +81,8 @@ module RailsSettings
70
81
 
71
82
  if readonly
72
83
  define_singleton_method(key) do
73
- send(:_convert_string_to_typeof_value, type, default, separator: separator)
84
+ result = default.is_a?(Proc) ? default.call : default
85
+ send(:_convert_string_to_typeof_value, type, result, separator: separator)
74
86
  end
75
87
  else
76
88
  define_singleton_method(key) do
@@ -89,7 +101,7 @@ module RailsSettings
89
101
  end
90
102
 
91
103
  define_singleton_method("#{key}=") do |value|
92
- var_name = key.to_s
104
+ var_name = key
93
105
 
94
106
  record = find_by(var: var_name) || new(var: var_name)
95
107
  value = send(:_convert_string_to_typeof_value, type, value, separator: separator)
@@ -99,6 +111,15 @@ module RailsSettings
99
111
 
100
112
  value
101
113
  end
114
+
115
+ if validates
116
+ validates[:if] = proc { |item| item.var.to_s == key }
117
+ send(:validates, key, **validates)
118
+
119
+ define_method(:read_attribute_for_validation) do |_key|
120
+ self.value
121
+ end
122
+ end
102
123
  end
103
124
 
104
125
  if type == :boolean
@@ -106,6 +127,13 @@ module RailsSettings
106
127
  send(key)
107
128
  end
108
129
  end
130
+
131
+ # delegate instance get method to class for support:
132
+ # setting = Setting.new
133
+ # setting.admin_emails
134
+ define_method(key) do
135
+ self.class.public_send(key)
136
+ end
109
137
  end
110
138
 
111
139
  def _convert_string_to_typeof_value(type, value, separator: nil)
@@ -113,19 +141,15 @@ module RailsSettings
113
141
 
114
142
  case type
115
143
  when :boolean
116
- value == "true" || value == "1" || value == 1 || value == true
144
+ ["true", "1", 1, true].include?(value)
117
145
  when :array
118
146
  value.split(separator || SEPARATOR_REGEXP).reject { |str| str.empty? }.map(&:strip)
119
147
  when :hash
120
148
  value = begin
121
- begin
122
- YAML.load(value).to_h
123
- rescue StandardError
124
- eval(value).to_h
125
- end
126
- rescue StandardError
127
- {}
128
- end
149
+ YAML.safe_load(value).to_h
150
+ rescue
151
+ {}
152
+ end
129
153
  value.deep_stringify_keys!
130
154
  ActiveSupport::HashWithIndifferentAccess.new(value)
131
155
  when :integer
@@ -146,12 +170,12 @@ module RailsSettings
146
170
  return nil
147
171
  end
148
172
 
149
- _all_settings[var_name.to_s]
173
+ _all_settings[var_name]
150
174
  end
151
175
 
152
176
  def _table_exists?
153
177
  table_exists?
154
- rescue => e
178
+ rescue
155
179
  false
156
180
  end
157
181
 
@@ -160,13 +184,11 @@ module RailsSettings
160
184
  end
161
185
 
162
186
  def _all_settings
163
- RequestCache.settings ||= begin
164
- Rails.cache.fetch(cache_key, expires_in: 1.week) do
165
- vars = unscoped.select("var, value")
166
- result = {}
167
- vars.each { |record| result[record.var] = record.value }
168
- result.with_indifferent_access
169
- end
187
+ RequestCache.settings ||= Rails.cache.fetch(cache_key, expires_in: 1.week) do
188
+ vars = unscoped.select("var, value")
189
+ result = {}
190
+ vars.each { |record| result[record.var] = record.value }
191
+ result.with_indifferent_access
170
192
  end
171
193
  end
172
194
  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.4.1"
6
+ "2.6.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.4.1
4
+ version: 2.6.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-06-21 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.1.2
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: []