rails-settings-cached 0.5.6 → 0.7.0

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
- SHA1:
3
- metadata.gz: b57a0a5ecf132300eb30437cecef1d72ac4a6850
4
- data.tar.gz: 0819f21de6cb043141b20ff39ddd4c212aabd758
2
+ SHA256:
3
+ metadata.gz: ac720065903da7de8fed10d171d0145ddeabb6b7d7f0a1b6c66f7e497c79ddb1
4
+ data.tar.gz: 2b20fdde2d824978ef981935b88faf7e3773469bacaa7520dcbcf59376bf0d76
5
5
  SHA512:
6
- metadata.gz: b26625a6a49cc7413f18201e454374a6de07523705efd6eedd7d889aa464f2f07a057a541a277eba1fcfc1ad6cc791c4221ce6e84b35c2004cb37d86fdb661ad
7
- data.tar.gz: d2c7146010da954ef4b8010b5a3fe7bd92a9c6c100c389a8db3c834fd90429c64a648387f6d5885c414f13b407f4cde974b382d13c6a089cc5dc0373780ef7d2
6
+ metadata.gz: eab7e6fb1eb995cf1d4e548812964ca6ac342e47c2792598f3db835b6611c31b13dd89e8d0973cf545799dbfeb8aa5ef5bed307a0559ee82484a37ff4df01ceb
7
+ data.tar.gz: 67139f1e6fea2edc490f43fa7a782a245a1b40b82ece38e4bcb479e18752511f2420131add354a48f5140ebf7130bf1ba8af6349336fa483d6e809625f80a7a6
data/README.md CHANGED
@@ -1,202 +1,284 @@
1
- # Settings Gem
2
-
3
- This is improved from [rails-settings](https://github.com/ledermann/rails-settings),
4
- added caching for all settings. Settings is a plugin that makes managing a table of
5
- global key, value pairs easy. Think of it like a global Hash stored in your database,
6
- that uses simple ActiveRecord like methods for manipulation. Keep track of any global
7
- setting that you dont want to hard code into your rails app. You can store any kind
8
- of object. Strings, numbers, arrays, or any object.
9
-
10
- ## Status
11
-
12
- [![Gem Version](https://badge.fury.io/rb/rails-settings-cached.svg)](https://rubygems.org/gems/rails-settings-cached) [![CI Status](https://api.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)
13
-
14
- ## Setup
15
-
16
- Edit your Gemfile:
17
-
18
- ```ruby
19
- gem 'rails-settings-cached', "~> 0.5.6"
20
- ```
21
-
22
- Older Rails versions:
23
-
24
- ```rb
25
- # 4.1.x
26
- gem "rails-settings-cached", "~> 0.4.0"
27
- # 4.0.x
28
- gem "rails-settings-cached", "0.3.1"
29
- # 3.x
30
- gem "rails-settings-cached", "0.2.4"
31
- ```
32
-
33
- Generate your settings:
34
-
35
- ```bash
36
- $ rails g settings:install
37
- ```
38
-
39
- If you want custom model name:
40
-
41
- ```bash
42
- $ rails g settings:install MySetting
43
- ```
44
-
45
- Now just put that migration in the database with:
46
-
47
- ```bash
48
- rake db:migrate
49
- ```
50
-
51
- ## Usage
52
-
53
- The syntax is easy. First, lets create some settings to keep track of:
54
-
55
- ```ruby
56
- Setting.admin_password = 'supersecret'
57
- Setting.date_format = '%m %d, %Y'
58
- Setting.cocktails = ['Martini', 'Screwdriver', 'White Russian']
59
- Setting.foo = 123
60
- Setting.credentials = { :username => 'tom', :password => 'secret' }
61
- ```
62
-
63
- Now lets read them back:
64
-
65
- ```ruby
66
- Setting.foo # returns 123
67
- ```
68
-
69
- Changing an existing setting is the same as creating a new setting:
70
-
71
- ```ruby
72
- Setting.foo = 'super duper bar'
73
- ```
74
-
75
- For changing an existing setting which is a Hash, you can merge new values with existing ones:
76
-
77
- ```ruby
78
- Setting.merge!(:credentials, :password => 'topsecret')
79
- Setting.credentials # returns { :username => 'tom', :password => 'topsecret' }
80
- ```
81
-
82
- Decide you dont want to track a particular setting anymore?
83
-
84
- ```ruby
85
- Setting.destroy :foo
86
- Setting.foo # returns nil
87
- ```
88
-
89
- Want a list of all the settings?
90
- ```ruby
91
- # Rails 4.1.x
92
- Setting.get_all
93
- # Rails 3.x and 4.0.x
94
- Setting.all
95
- # returns {'admin_password' => 'super_secret', 'date_format' => '%m %d, %Y'}
96
- ```
97
-
98
- You need name spaces and want a list of settings for a give name space? Just choose your prefered named space delimiter and use `Setting.get_all` (`Settings.all` for # Rails 3.x and 4.0.x) like this:
99
-
100
- ```ruby
101
- Setting['preferences.color'] = :blue
102
- Setting['preferences.size'] = :large
103
- Setting['license.key'] = 'ABC-DEF'
104
- # Rails 4.1.x
105
- Setting.get_all('preferences.')
106
- # Rails 3.x and 4.0.x
107
- Setting.all('preferences.')
108
- # returns { 'preferences.color' => :blue, 'preferences.size' => :large }
109
- ```
110
-
111
- Set defaults for certain settings of your app. This will cause the defined settings to return with the
112
- Specified value even if they are **not in the database**. Make a new file in `config/initializers/default_settings.rb`
113
- with the following:
114
-
115
- ```ruby
116
- Setting.defaults[:some_setting] = 'footastic'
117
- Setting.where(:var => "some_setting").count
118
- => 0
119
- Setting.some_setting
120
- => "footastic"
121
- ```
122
-
123
- Init default value in database, this has indifferent with `Setting.defaults[:some_setting]`, this will **save the value into database**:
124
-
125
- ```ruby
126
- Setting.save_default(:some_key, "123")
127
- Setting.where(:var => "some_key").count
128
- => 1
129
- Setting.some_key
130
- => "123"
131
- ```
132
-
133
- Settings may be bound to any existing ActiveRecord object. Define this association like this:
134
- Notice! is not do caching in this version.
135
-
136
- ```ruby
137
- class User < ActiveRecord::Base
138
- include RailsSettings::Extend
139
- end
140
- ```
141
-
142
- Then you can set/get a setting for a given user instance just by doing this:
143
-
144
- ```ruby
145
- user = User.find(123)
146
- user.settings.color = :red
147
- user.settings.color # returns :red
148
- # Rails 4.1.x
149
- user.settings.get_all
150
- # Rails 3.x and 4.0.x
151
- user.settings.all
152
- # { "color" => :red }
153
- ```
154
-
155
- If you want to find users having or not having some settings, there are named scopes for this:
156
-
157
- ```ruby
158
- User.with_settings
159
- # => returns a scope of users having any setting
160
-
161
- User.with_settings_for('color')
162
- # => returns a scope of users having a 'color' setting
163
-
164
- User.without_settings
165
- # returns a scope of users having no setting at all (means user.settings.get_all == {})
166
-
167
- User.without_settings('color')
168
- # returns a scope of users having no 'color' setting (means user.settings.color == nil)
169
- ```
170
-
171
- Settings maybe dynamically scoped. For example, if you're using [apartment gem](https://github.com/influitive/apartment) for multitenancy, you may not want tenants to share settings:
172
-
173
- ```ruby
174
- class Settings < RailsSettings::CachedSettings
175
- cache_prefix { Apartment::Tenant.current }
176
- ...
177
- end
178
- ```
179
-
180
- -----
181
-
182
- ## How to create a list, form to manage Settings?
183
-
184
- If you want create an admin interface to editing the Settings, you can try methods in follow:
185
-
186
- ```ruby
187
- class SettingsController < ApplicationController
188
- def index
189
- # to get all items for render list
190
- @settings = Setting.unscoped
191
- end
192
-
193
- def edit
194
- @setting = Setting.unscoped.find(params[:id])
195
- end
196
- end
197
- ```
198
-
199
-
200
- Also you may use [rails-settings-ui](https://github.com/accessd/rails-settings-ui) gem
201
- for building ready to using interface with validations.
202
-
1
+ # Rails Settings Cached
2
+
3
+ This is improved from [rails-settings](https://github.com/ledermann/rails-settings),
4
+ added caching for all settings. Settings is a plugin that makes managing a table of
5
+ global key, value pairs easy. Think of it like a global Hash stored in your database,
6
+ that uses simple ActiveRecord like methods for manipulation. Keep track of any global
7
+ setting that you dont want to hard code into your rails app. You can store any kind
8
+ of object. Strings, numbers, arrays, or any object.
9
+
10
+ ## Status
11
+
12
+ [![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)
13
+
14
+ ## Setup
15
+
16
+ Edit your Gemfile:
17
+
18
+ ```ruby
19
+ gem "rails-settings-cached"
20
+ ```
21
+
22
+ Generate your settings:
23
+
24
+ ```bash
25
+ $ rails g settings:install
26
+ ```
27
+
28
+ If you want custom model name:
29
+
30
+ ```bash
31
+ $ rails g settings:install
32
+ ```
33
+
34
+ Or use a custom name:
35
+
36
+ ```bash
37
+ $ rails g settings:install SiteConfig
38
+ ```
39
+
40
+ You will get `app/models/setting.rb`
41
+
42
+ ```rb
43
+ class Setting < RailsSettings::Base
44
+ source Rails.root.join("config/app.yml")
45
+ # cache_prefix { "v1" }
46
+ end
47
+ ```
48
+
49
+ Now just put that migration in the database with:
50
+
51
+ ```bash
52
+ rake db:migrate
53
+ ```
54
+
55
+ ## Usage
56
+
57
+ The syntax is easy. First, lets create some settings to keep track of:
58
+
59
+ ```ruby
60
+ Setting.admin_password = 'supersecret'
61
+ Setting.date_format = '%m %d, %Y'
62
+ Setting.cocktails = ['Martini', 'Screwdriver', 'White Russian']
63
+ Setting.foo = 123
64
+ Setting.credentials = { :username => 'tom', :password => 'secret' }
65
+ ```
66
+
67
+ Now lets read them back:
68
+
69
+ ```ruby
70
+ Setting.foo # returns 123
71
+ ```
72
+
73
+ Changing an existing setting is the same as creating a new setting:
74
+
75
+ ```ruby
76
+ Setting.foo = 'super duper bar'
77
+ ```
78
+
79
+ Decide you dont want to track a particular setting anymore?
80
+
81
+ ```ruby
82
+ Setting.destroy :foo
83
+ Setting.foo # returns nil
84
+ ```
85
+
86
+ Want a list of all the settings?
87
+ ```ruby
88
+ Setting.get_all
89
+ ```
90
+
91
+ You need name spaces and want a list of settings for a give name space? Just choose your prefered named space delimiter and use `Setting.get_all` (`Settings.all` for # Rails 3.x and 4.0.x) like this:
92
+
93
+ ```ruby
94
+ Setting['preferences.color'] = :blue
95
+ Setting['preferences.size'] = :large
96
+ Setting['license.key'] = 'ABC-DEF'
97
+ # Rails 4.1.x
98
+ Setting.get_all('preferences.')
99
+ # Rails 3.x and 4.0.x
100
+ Setting.all('preferences.')
101
+ # returns { 'preferences.color' => :blue, 'preferences.size' => :large }
102
+ ```
103
+
104
+ ## Extend a model
105
+
106
+ Settings may be bound to any existing ActiveRecord object. Define this association like this:
107
+ Notice! is not do caching in this version.
108
+
109
+ ```ruby
110
+ class User < ActiveRecord::Base
111
+ include RailsSettings::Extend
112
+ end
113
+ ```
114
+
115
+ Then you can set/get a setting for a given user instance just by doing this:
116
+
117
+ ```ruby
118
+ user = User.find(123)
119
+ user.settings.color = :red
120
+ user.settings.color # returns :red
121
+ user.settings.get_all
122
+ # { "color" => :red }
123
+ ```
124
+
125
+ If you want to find users having or not having some settings, there are named scopes for this:
126
+
127
+ ```ruby
128
+ User.with_settings
129
+ # => returns a scope of users having any setting
130
+
131
+ User.with_settings_for('color')
132
+ # => returns a scope of users having a 'color' setting
133
+
134
+ User.without_settings
135
+ # returns a scope of users having no setting at all (means user.settings.get_all == {})
136
+
137
+ User.without_settings('color')
138
+ # returns a scope of users having no 'color' setting (means user.settings.color == nil)
139
+ ```
140
+
141
+ ## Default settings
142
+
143
+ Sometimes you may want define default settings.
144
+
145
+ RailsSettings has generate a config YAML file in:
146
+
147
+ ```yml
148
+ # config/app.yml
149
+ defaults: &defaults
150
+ github_token: "123456"
151
+ twitter_token: "<%= ENV["TWITTER_TOKEN"] %>"
152
+ foo:
153
+ bar: "Foo bar"
154
+
155
+ development:
156
+ <<: *defaults
157
+
158
+ test:
159
+ <<: *defaults
160
+
161
+ production:
162
+ <<: *defaults
163
+ ```
164
+
165
+ And you can use by `Setting` model:
166
+
167
+ ```
168
+ Setting.github_token
169
+ => "123456"
170
+ Setting.github_token = "654321"
171
+ # Save into database.
172
+ Setting.github_token
173
+ # Read from databae / caching.
174
+ => "654321"
175
+ Setting['foo.bar']
176
+ => 'Foo bar'
177
+ ```
178
+
179
+ NOTE: YAML setting it also under the cache scope, when you restart Rails application, cache will expire,
180
+ so when you want change default config, you need restart Rails application server.
181
+
182
+ ### Caching flow:
183
+
184
+ ```
185
+ Setting.foo -> Check Cache -> Exist - Write Cache -> Return
186
+ |
187
+ Check DB -> Exist -> Write Cache -> Return
188
+ |
189
+ Check Default -> Exist -> Write Cache -> Return
190
+ |
191
+ Return nil
192
+ ```
193
+
194
+ ## Change cache key
195
+
196
+ When `config/app.yml` has changed, you may need change the cache prefix to expires caches.
197
+
198
+ ```ruby
199
+ class Setting < RailsSettings::Base
200
+ cache_prefix { 'you-prefix' }
201
+ ...
202
+ end
203
+ ```
204
+
205
+ -----
206
+
207
+ ## How to create a list, form to manage Settings?
208
+
209
+ If you want create an admin interface to editing the Settings, you can try methods in follow:
210
+
211
+ config/routes.rb
212
+
213
+ ```rb
214
+ namespace :admin do
215
+ resources :settings
216
+ end
217
+ ```
218
+
219
+
220
+ app/controllers/admin/settings_controller.rb
221
+
222
+ ```rb
223
+ module Admin
224
+ class SettingsController < ApplicationController
225
+ before_action :get_setting, only: [:edit, :update]
226
+
227
+ def index
228
+ @settings = Setting.get_all
229
+ end
230
+
231
+ def edit
232
+ end
233
+
234
+ def update
235
+ if @setting.value != params[:setting][:value]
236
+ @setting.value = params[:setting][:value]
237
+ @setting.save
238
+ redirect_to admin_settings_path, notice: 'Setting has updated.'
239
+ else
240
+ redirect_to admin_settings_path
241
+ end
242
+ end
243
+
244
+ def get_setting
245
+ @setting = Setting.find_by(var: params[:id]) || Setting.new(var: params[:id])
246
+ end
247
+ end
248
+ end
249
+ ```
250
+
251
+ app/views/admin/settings/index.html.erb
252
+
253
+ ```erb
254
+ <table>
255
+ <tr>
256
+ <th>Key</th>
257
+ <th></th>
258
+ </tr>
259
+ <% @settings.each_key do |key| %>
260
+ <tr>
261
+ <td><%= key %></td>
262
+ <td><%= link_to 'edit', edit_admin_setting_path(key) %></td>
263
+ </tr>
264
+ <% end %>
265
+ </table>
266
+ ```
267
+
268
+ app/views/admin/settings/edit.html.erb
269
+
270
+ ```erb
271
+ <%= form_for(@setting, url: admin_setting_path(@setting.var), method: 'patch') do |f| %>
272
+ <label><%= @setting.var %></label>
273
+ <%= f.text_area :value, rows: 10 %>
274
+ <%= f.submit %>
275
+ <% end %>
276
+ ```
277
+
278
+ Also you may use [rails-settings-ui](https://github.com/accessd/rails-settings-ui) gem
279
+ for building ready to using interface with validations,
280
+ or [activeadmin_settings_cached](https://github.com/artofhuman/activeadmin_settings_cached) gem if you use [activeadmin](https://github.com/activeadmin/activeadmin).
281
+
282
+ ## Use case:
283
+
284
+ - [ruby-china/ruby-china](https://github.com/ruby-china/ruby-china)
@@ -3,7 +3,7 @@ require 'rails/generators/migration'
3
3
 
4
4
  module Settings
5
5
  class InstallGenerator < Rails::Generators::NamedBase
6
- desc "Generate RailsSettings files."
6
+ desc 'Generate RailsSettings files.'
7
7
  include Rails::Generators::Migration
8
8
 
9
9
  argument :name, type: :string, default: 'setting'
@@ -26,8 +26,17 @@ module Settings
26
26
  end
27
27
 
28
28
  def install_setting
29
- template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb"), force: true
30
- migration_template 'migration.rb', 'db/migrate/create_settings.rb'
29
+ template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb")
30
+ template 'app.yml', File.join('config', 'app.yml')
31
+ migration_template 'migration.rb', 'db/migrate/create_settings.rb', migration_version: migration_version
32
+ end
33
+
34
+ def rails5?
35
+ Rails.version.start_with? '5'
36
+ end
37
+
38
+ def migration_version
39
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]" if rails5?
31
40
  end
32
41
  end
33
42
  end
@@ -0,0 +1,13 @@
1
+ # config/app.yml for rails-settings-cached
2
+ defaults: &defaults
3
+ foo: "Foo"
4
+ bar: 123
5
+
6
+ development:
7
+ <<: *defaults
8
+
9
+ test:
10
+ <<: *defaults
11
+
12
+ production:
13
+ <<: *defaults
@@ -1,4 +1,4 @@
1
- class CreateSettings < ActiveRecord::Migration
1
+ class CreateSettings < ActiveRecord::Migration<%= migration_version %>
2
2
  def self.up
3
3
  create_table :settings do |t|
4
4
  t.string :var, null: false
@@ -1,3 +1,7 @@
1
1
  # RailsSettings Model
2
- class <%= class_name %> < RailsSettings::CachedSettings
2
+ class <%= class_name %> < RailsSettings::Base
3
+ source Rails.root.join("config/app.yml")
4
+
5
+ # When config/app.yml has changed, you need change this prefix to v2, v3 ... to expires caches
6
+ # cache_prefix { "v1" }
3
7
  end
@@ -1,112 +1,44 @@
1
1
  module RailsSettings
2
- class Base < ActiveRecord::Base
3
- self.table_name = table_name_prefix + 'settings'
4
-
5
- class SettingNotFound < RuntimeError; end
6
-
7
- cattr_accessor :defaults
8
- @@defaults = {}.with_indifferent_access
9
-
10
- belongs_to :thing, polymorphic: true
11
-
12
- # Support old plugin
13
- if defined?(SettingsDefaults::DEFAULTS)
14
- @@defaults = SettingsDefaults::DEFAULTS.with_indifferent_access
2
+ class Base < Settings
3
+ def rewrite_cache
4
+ Rails.cache.write(cache_key, value)
15
5
  end
16
6
 
17
- # get the value field, YAML decoded
18
- def value
19
- YAML.load(self[:value]) if self[:value].present?
7
+ def expire_cache
8
+ Rails.cache.delete(cache_key)
20
9
  end
21
10
 
22
- # set the value field, YAML encoded
23
- def value=(new_value)
24
- self[:value] = new_value.to_yaml
11
+ def cache_key
12
+ self.class.cache_key(var, thing)
25
13
  end
26
14
 
27
15
  class << self
28
- # get or set a variable with the variable as the called method
29
- def method_missing(method, *args)
30
- method_name = method.to_s
31
- super(method, *args)
32
- rescue NoMethodError
33
- # set a value for a variable
34
- if method_name[-1] == '='
35
- var_name = method_name.sub('=', '')
36
- value = args.first
37
- self[var_name] = value
38
- else
39
- # retrieve a value
40
- self[method_name]
41
- end
16
+ def cache_prefix(&block)
17
+ @cache_prefix = block
42
18
  end
43
19
 
44
- # destroy the specified settings record
45
- def destroy(var_name)
46
- var_name = var_name.to_s
47
- obj = object(var_name)
48
- raise SettingNotFound, "Setting variable \"#{var_name}\" not found" if obj.nil?
49
-
50
- obj.destroy
51
- true
20
+ def cache_key(var_name, scope_object)
21
+ scope = ["rails_settings_cached"]
22
+ scope << @cache_prefix.call if @cache_prefix
23
+ scope << "#{scope_object.class.name}-#{scope_object.id}" if scope_object
24
+ scope << var_name.to_s
25
+ scope.join('/')
52
26
  end
53
27
 
54
- # retrieve all settings as a hash (optionally starting with a given namespace)
55
- def get_all(starting_with = nil)
56
- vars = thing_scoped.select('var, value')
57
- vars = vars.where("var LIKE '#{starting_with}%'") if starting_with
58
-
59
- result = {}
60
- vars.each do |record|
61
- result[record.var] = record.value
28
+ def [](key)
29
+ return super(key) unless rails_initialized?
30
+ val = Rails.cache.fetch(cache_key(key, @object)) do
31
+ super(key)
62
32
  end
63
- default_keys = @@defaults.keys
64
- default_keys = default_keys.select {|k| k.start_with? starting_with } if starting_with
65
- result.merge! @@defaults.slice(*(default_keys - result.keys))
66
-
67
- result.with_indifferent_access
68
- end
69
-
70
- def where(sql = nil)
71
- vars = thing_scoped.where(sql) if sql
72
- vars
73
- end
74
-
75
- # get a setting value by [] notation
76
- def [](var_name)
77
- object(var_name).try(:value) || @@defaults[var_name.to_s]
33
+ val
78
34
  end
79
35
 
80
36
  # set a setting value by [] notation
81
37
  def []=(var_name, value)
82
- var_name = var_name.to_s
83
-
84
- record = object(var_name) || thing_scoped.new(var: var_name)
85
- record.value = value
86
- record.save!
87
-
38
+ super
39
+ Rails.cache.write(cache_key(var_name, @object), value)
88
40
  value
89
41
  end
90
-
91
- def merge!(var_name, hash_value)
92
- raise ArgumentError unless hash_value.is_a?(Hash)
93
-
94
- old_value = self[var_name] || {}
95
- raise TypeError, "Existing value is not a hash, can't merge!" unless old_value.is_a?(Hash)
96
-
97
- new_value = old_value.merge(hash_value)
98
- self[var_name] = new_value if new_value != old_value
99
-
100
- new_value
101
- end
102
-
103
- def object(var_name)
104
- thing_scoped.where(var: var_name.to_s).first
105
- end
106
-
107
- def thing_scoped
108
- unscoped.where('thing_type is NULL and thing_id is NULL')
109
- end
110
42
  end
111
43
  end
112
44
  end
@@ -0,0 +1,40 @@
1
+ require 'digest/md5'
2
+
3
+ module RailsSettings
4
+ class Default < ::Hash
5
+ class MissingKey < StandardError; end
6
+
7
+ class << self
8
+ def enabled?
9
+ source_path && File.exist?(source_path)
10
+ end
11
+
12
+ def source(value = nil)
13
+ @source ||= value
14
+ end
15
+
16
+ def source_path
17
+ @source || Rails.root.join('config/app.yml')
18
+ end
19
+
20
+ def [](key)
21
+ # foo.bar.dar Nested fetch value
22
+ return instance[key] if instance.key?(key)
23
+ keys = key.to_s.split('.')
24
+ instance.dig(*keys)
25
+ end
26
+
27
+ def instance
28
+ return @instance if defined? @instance
29
+ @instance = new
30
+ end
31
+ end
32
+
33
+ def initialize
34
+ content = open(self.class.source_path).read
35
+ hash = content.empty? ? {} : YAML.load(ERB.new(content).result).to_hash
36
+ hash = hash[Rails.env] || {}
37
+ replace hash
38
+ end
39
+ end
40
+ end
@@ -9,7 +9,7 @@ module RailsSettings
9
9
  .select("DISTINCT #{table_name}.*")
10
10
  }
11
11
 
12
- scope :with_settings_for, lambda { |var|
12
+ scope :with_settings_for, lambda { |var|
13
13
  joins("JOIN settings ON (settings.thing_id = #{table_name}.#{primary_key} AND
14
14
  settings.thing_type = '#{base_class.name}') AND settings.var = '#{var}'")
15
15
  }
@@ -20,7 +20,7 @@ module RailsSettings
20
20
  .where('settings.id IS NULL')
21
21
  }
22
22
 
23
- scope :without_settings_for, lambda { |var|
23
+ scope :without_settings_for, lambda { |var|
24
24
  where('settings.id IS NULL')
25
25
  .joins("LEFT JOIN settings ON (settings.thing_id = #{table_name}.#{primary_key} AND
26
26
  settings.thing_type = '#{base_class.name}') AND settings.var = '#{var}'")
@@ -0,0 +1,8 @@
1
+ module RailsSettings
2
+ class Railtie < Rails::Railtie
3
+ initializer 'rails_settings.active_record.initialization' do
4
+ RailsSettings::Base.after_commit :rewrite_cache, on: %i(create update)
5
+ RailsSettings::Base.after_commit :expire_cache, on: %i(destroy)
6
+ end
7
+ end
8
+ end
@@ -1,5 +1,5 @@
1
1
  module RailsSettings
2
- class ScopedSettings < CachedSettings
2
+ class ScopedSettings < Base
3
3
  def self.for_thing(object)
4
4
  @object = object
5
5
  self
@@ -1,9 +1,119 @@
1
1
  module RailsSettings
2
- class Settings < Base
3
- def self.inherited(subclass)
4
- Kernel.warn 'DEPRECATION WARNING: RailsSettings::Settings is deprecated and it will removed in 0.6.0. ' <<
5
- 'Please use RailsSettings::Base instead.'
6
- super(subclass)
2
+ class Settings < ActiveRecord::Base
3
+ self.table_name = table_name_prefix + 'settings'
4
+
5
+ class SettingNotFound < RuntimeError; end
6
+
7
+ belongs_to :thing, polymorphic: true
8
+
9
+ # get the value field, YAML decoded
10
+ def value
11
+ YAML.load(self[:value]) if self[:value].present?
12
+ end
13
+
14
+ # set the value field, YAML encoded
15
+ def value=(new_value)
16
+ self[:value] = new_value.to_yaml
17
+ end
18
+
19
+ class << self
20
+ # get or set a variable with the variable as the called method
21
+ # rubocop:disable Style/MethodMissing
22
+ def method_missing(method, *args)
23
+ method_name = method.to_s
24
+ super(method, *args)
25
+ rescue NoMethodError
26
+ # set a value for a variable
27
+ if method_name[-1] == '='
28
+ var_name = method_name.sub('=', '')
29
+ value = args.first
30
+ self[var_name] = value
31
+ else
32
+ # retrieve a value
33
+ self[method_name]
34
+ end
35
+ end
36
+
37
+ # destroy the specified settings record
38
+ def destroy(var_name)
39
+ var_name = var_name.to_s
40
+ obj = object(var_name)
41
+ raise SettingNotFound, "Setting variable \"#{var_name}\" not found" if obj.nil?
42
+
43
+ obj.destroy
44
+ true
45
+ end
46
+
47
+ # retrieve all settings as a hash (optionally starting with a given namespace)
48
+ def get_all(starting_with = nil)
49
+ vars = thing_scoped.select('var, value')
50
+ vars = vars.where("var LIKE '#{starting_with}%'") if starting_with
51
+ result = {}
52
+ vars.each { |record| result[record.var] = record.value }
53
+ result.reverse_merge!(default_settings(starting_with))
54
+ result.with_indifferent_access
55
+ end
56
+
57
+ def where(sql = nil)
58
+ vars = thing_scoped.where(sql) if sql
59
+ vars
60
+ end
61
+
62
+ # get a setting value by [] notation
63
+ def [](var_name)
64
+ val = object(var_name)
65
+ return val.value if val
66
+ return Default[var_name] if Default.enabled?
67
+ end
68
+
69
+ # set a setting value by [] notation
70
+ def []=(var_name, value)
71
+ var_name = var_name.to_s
72
+
73
+ record = object(var_name) || thing_scoped.new(var: var_name)
74
+ record.value = value
75
+ record.save!
76
+
77
+ value
78
+ end
79
+
80
+ def merge!(var_name, hash_value)
81
+ raise ArgumentError unless hash_value.is_a?(Hash)
82
+
83
+ old_value = self[var_name] || {}
84
+ raise TypeError, "Existing value is not a hash, can't merge!" unless old_value.is_a?(Hash)
85
+
86
+ new_value = old_value.merge(hash_value)
87
+ self[var_name] = new_value if new_value != old_value
88
+
89
+ new_value
90
+ end
91
+
92
+ def object(var_name)
93
+ return nil unless rails_initialized?
94
+ return nil unless table_exists?
95
+ thing_scoped.where(var: var_name.to_s).first
96
+ end
97
+
98
+ def thing_scoped
99
+ unscoped.where('thing_type is NULL and thing_id is NULL')
100
+ end
101
+
102
+ def source(filename)
103
+ Default.source(filename)
104
+ end
105
+
106
+ def rails_initialized?
107
+ Rails.application && Rails.application.initialized?
108
+ end
109
+
110
+ private
111
+
112
+ def default_settings(starting_with = nil)
113
+ return {} unless Default.enabled?
114
+ return Default.instance if starting_with.nil?
115
+ Default.instance.select { |key, _| key.to_s.start_with?(starting_with) }
116
+ end
7
117
  end
8
118
  end
9
119
  end
@@ -1,7 +1,7 @@
1
1
  module RailsSettings
2
2
  class << self
3
3
  def version
4
- "0.5.6"
4
+ '0.7.0'
5
5
  end
6
6
  end
7
7
  end
@@ -1,15 +1,10 @@
1
- require_relative 'rails-settings/base'
2
1
  require_relative 'rails-settings/settings'
3
- require_relative 'rails-settings/cached_settings'
2
+ require_relative 'rails-settings/base'
4
3
  require_relative 'rails-settings/scoped_settings'
4
+ require_relative 'rails-settings/default'
5
5
  require_relative 'rails-settings/extend'
6
+ require_relative 'rails-settings/railtie'
6
7
  require_relative 'rails-settings/version'
7
8
 
8
9
  module RailsSettings
9
- class Railtie < Rails::Railtie
10
- initializer "rails_settings.active_record.initialization" do
11
- RailsSettings::CachedSettings.after_commit :rewrite_cache, on: %i(create update)
12
- RailsSettings::CachedSettings.after_commit :expire_cache, on: %i(destroy)
13
- end
14
- end
15
10
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-settings-cached
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.6
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Lee
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2016-04-11 00:00:00.000000000 Z
14
+ date: 2018-06-13 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rails
@@ -27,6 +27,76 @@ dependencies:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
29
  version: 4.2.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: sqlite3
32
+ requirement: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ type: :development
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ - !ruby/object:Gem::Dependency
45
+ name: rubocop
46
+ requirement: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - '='
49
+ - !ruby/object:Gem::Version
50
+ version: 0.46.0
51
+ type: :development
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - '='
56
+ - !ruby/object:Gem::Version
57
+ version: 0.46.0
58
+ - !ruby/object:Gem::Dependency
59
+ name: simplecov
60
+ requirement: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ - !ruby/object:Gem::Dependency
73
+ name: rspec
74
+ requirement: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ - !ruby/object:Gem::Dependency
87
+ name: codecov
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ type: :development
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
30
100
  description: "\n This is improved from rails-settings, added caching.\n Settings
31
101
  plugin for Rails that makes managing a table of global key,\n value pairs easy.
32
102
  Think of it like a global Hash stored in you database,\n that uses simple ActiveRecord
@@ -40,12 +110,14 @@ extra_rdoc_files: []
40
110
  files:
41
111
  - README.md
42
112
  - lib/generators/settings/install_generator.rb
113
+ - lib/generators/settings/templates/app.yml
43
114
  - lib/generators/settings/templates/migration.rb
44
115
  - lib/generators/settings/templates/model.rb
45
116
  - lib/rails-settings-cached.rb
46
117
  - lib/rails-settings/base.rb
47
- - lib/rails-settings/cached_settings.rb
118
+ - lib/rails-settings/default.rb
48
119
  - lib/rails-settings/extend.rb
120
+ - lib/rails-settings/railtie.rb
49
121
  - lib/rails-settings/scoped_settings.rb
50
122
  - lib/rails-settings/settings.rb
51
123
  - lib/rails-settings/version.rb
@@ -60,7 +132,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
60
132
  requirements:
61
133
  - - ">="
62
134
  - !ruby/object:Gem::Version
63
- version: '2.1'
135
+ version: '2.3'
64
136
  required_rubygems_version: !ruby/object:Gem::Requirement
65
137
  requirements:
66
138
  - - ">="
@@ -68,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
140
  version: '0'
69
141
  requirements: []
70
142
  rubyforge_project:
71
- rubygems_version: 2.6.3
143
+ rubygems_version: 2.7.6
72
144
  signing_key:
73
145
  specification_version: 4
74
146
  summary: Settings plugin for Rails that makes managing a table of global keys.
@@ -1,54 +0,0 @@
1
- module RailsSettings
2
- class CachedSettings < Base
3
- def rewrite_cache
4
- Rails.cache.write(cache_key, value)
5
- end
6
-
7
- def expire_cache
8
- Rails.cache.delete(cache_key)
9
- end
10
-
11
- def cache_key
12
- self.class.cache_key(var, thing)
13
- end
14
-
15
- class << self
16
- def cache_prefix(&block)
17
- @cache_prefix = block
18
- end
19
-
20
- def cache_key(var_name, scope_object)
21
- scope = "rails_settings_cached:"
22
- scope << "#{@cache_prefix.call}:" if @cache_prefix
23
- scope << "#{scope_object.class.name}-#{scope_object.id}:" if scope_object
24
- scope << "#{var_name}"
25
- end
26
-
27
- def [](var_name)
28
- value = Rails.cache.fetch(cache_key(var_name, @object)) do
29
- super(var_name)
30
- end
31
-
32
- if value.nil?
33
- @@defaults[var_name.to_s] if value.nil?
34
- else
35
- value
36
- end
37
- end
38
-
39
- # set a setting value by [] notation
40
- def []=(var_name, value)
41
- super
42
-
43
- Rails.cache.write(cache_key(var_name, @object),value)
44
-
45
- value
46
- end
47
-
48
- def save_default(key, value)
49
- return false unless self[key].nil?
50
- self[key] = value
51
- end
52
- end
53
- end
54
- end