rails-settings-cached 0.5.6 → 0.7.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
- 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