Rails Settings Cached
This a plugin that makes 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. You can store any kind of object. Strings, numbers, arrays, or any object.
Installation
Edit your Gemfile:
$ bundle add rails-settings-cached
Generate your settings:
$ rails g settings:install
# Or use a custom name:
$ rails g settings:install AppConfig
You will get app/models/setting.rb
class Setting < RailsSettings::Base
# cache_prefix { "v1" }
field :app_name, default: "Rails Settings"
field :host, default: "http://example.com", readonly: true
field :default_locale, default: "zh-CN"
field :readonly_item, type: :integer, default: 100, readonly: true
field :user_limits, type: :integer, default: 20
field :exchange_rate, type: :float, default: 0.123
field :admin_emails, type: :array, default: %w[admin@rubyonrails.org]
field :captcha_enable, type: :boolean, default: true
# Override array separator, default: /[\n,]/ split with \n or comma.
field :tips, type: :array, separator: /[\n]+/
field :notification_options, type: :hash, default: {
send_all: true,
logging: true,
sender_email: "foo@bar.com"
}
# lambda default value
field :welcome_message, type: :string, default: -> { "welcome to #{self.app_name}" }
end
You must use field
method to statement the setting keys, otherwise you can't use it.
Now just put that migration in the database with:
$ rails db:migrate
Usage
The syntax is easy. First, let's create some settings to keep track of:
irb > Setting.host
"http://example.com"
irb > Setting.app_name
"Rails Settings"
irb > Setting.app_name = "Rails Settings Cached"
irb > Setting.app_name
"Rails Settings Cached"
irb > Setting.user_limits
20
irb > Setting.user_limits = "30"
irb > Setting.user_limits
30
irb > Setting.user_limits = 45
irb > Setting.user_limits
45
irb > Setting.captcha_enable
1
irb > Setting.captcha_enable?
true
irb > Setting.captcha_enable = "0"
irb > Setting.captcha_enable
false
irb > Setting.captcha_enable = "1"
irb > Setting.captcha_enable
true
irb > Setting.captcha_enable = "false"
irb > Setting.captcha_enable
false
irb > Setting.captcha_enable = "true"
irb > Setting.captcha_enable
true
irb > Setting.captcha_enable?
true
irb > Setting.admin_emails
["admin@rubyonrails.org"]
irb > Setting.admin_emails = %w[foo@bar.com bar@dar.com]
irb > Setting.admin_emails
["foo@bar.com", "bar@dar.com"]
irb > Setting.admin_emails = "huacnlee@gmail.com,admin@admin.com\nadmin@rubyonrails.org"
irb > Setting.admin_emails
["huacnlee@gmail.com", "admin@admin.com", "admin@rubyonrails.org"]
irb > Setting.notification_options
{
send_all: true,
logging: true,
sender_email: "foo@bar.com"
}
irb > Setting.notification_options = {
sender_email: "notice@rubyonrails.org"
}
irb > Setting.notification_options
{
sender_email: "notice@rubyonrails.org"
}
Get defined fields
version 2.3+
# Get all keys
Setting.keys
=> ["app_name", "host", "default_locale", "readonly_item"]
# Get editable keys
Settng.editable_keys
=> ["app_name", "default_locale"]
# Get readonly keys
Setting.readonly_keys
=> ["host", "readonly_item"]
# Get options of field
Setting.get_field("host")
=> { key: "host", type: :string, default: "http://example.com", readonly: true }
Setting.get_field("app_name")
=> { key: "app_name", type: :string, default: "Rails Settings", readonly: false }
Use Setting in Rails initializing:
In version 2.3+
we allows you to use Setting before Rails is initialized.
For example config/initializers/devise.rb
Devise.setup do |config|
if Setting.omniauth_google_client_id.present?
config.omniauth :google_oauth2, Setting.omniauth_google_client_id, Setting.omniauth_google_client_secret
end
end
class Setting < RailsSettings::Base
field :omniauth_google_client_id, default: ENV["OMNIAUTH_GOOGLE_CLIENT_ID"]
field :omniauth_google_client_secret, default: ENV["OMNIAUTH_GOOGLE_CLIENT_SECRET"]
end
Readonly field
You may also want use Setting in these locations:
config/application.rb
config/environments/*.rb
If you want do that do that, the setting field must has readonly: true
.
For example:
class Setting < RailsSettings::Base
field :mailer_provider, default: (ENV["mailer_provider"] || "smtp"), readonly: true
field :mailer_options, type: :hash, readonly: true, default: {
address: ENV["mailer_options.address"],
port: ENV["mailer_options.port"],
domain: ENV["mailer_options.domain"],
user_name: ENV["mailer_options.user_name"],
password: ENV["mailer_options.password"],
authentication: ENV["mailer_options.authentication"] || "login",
enable_starttls_auto: ENV["mailer_options.enable_starttls_auto"]
}
end
Rails.application.configure do
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = Setting.mailer_options.deep_symbolize_keys
end
Caching flow:
Setting.host -> Check Cache -> Exist - Get value of key for cache -> Return
|
Fetch all key and values from DB -> Write Cache -> Get value of key for cache -> return
|
Return default value or nil
In each Setting keys call, we will load the cache/db and save in RequestStore to avoid hit cache/db.
Each key update will expire the cache, so do not add some frequent update key.
Change cache key
Some times you may need to force update cache, now you can use cache_prefix
class Setting < RailsSettings::Base
cache_prefix { "you-prefix" }
...
end
In testing, you need add Setting.clear_cache
for each Test case:
class ActiveSupport::TestCase
teardown do
Setting.clear_cache
end
end
How to manage Settings in the admin interface?
If you want to create an admin interface to editing the Settings, you can try methods in following:
config/routes.rb
namespace :admin do
resource :settings
end
app/controllers/admin/settings_controller.rb
module Admin
class SettingsController < ApplicationController
before_action :get_setting, only: [:edit, :update]
def create
setting_params.keys.each do |key|
Setting.send("#{key}=", setting_params[key].strip) unless setting_params[key].nil?
end
redirect_to settings_path, notice: "Setting was successfully updated."
end
private
def setting_params
params.require(:setting).permit(:host, :user_limits, :admin_emails,
:captcha_enable, :notification_options)
end
end
end
app/views/admin/settings/show.html.erb
<%= form_for(Setting.new, url: admin_settings_path) do |f| %>
<div class="form-group">
<label class="control-label">Host</label>
<%= f.text_field :host, value: Setting.host, class: "form-control", placeholder: "http://localhost" %>
</div>
<div class="form-group form-checkbox">
<label>
<%= f.check_box :captcha_enable, checked: Setting.captcha_enable? %>
Enable/Disable Captcha
</label>
</div>
<div class="form-group">
<label class="control-label">Admin Emails</label>
<%= f.text_area :admin_emails, value: Setting.admin_emails.join("\n"), class: "form-control" %>
</div>
<div class="form-group">
<label class="control-label">Notification options</label>
<%= f.text_area :notification_options, value: YAML.dump(Setting.notification_options), class: "form-control", style: "height: 180px;" %>
<div class="form-text">
Use YAML format to config the SMTP_html
</div>
</div>
<div>
<%= f.submit 'Update Settings' %>
</div>
<% end %>
Scoped Settings
🚨 BREAK CHANGES WARNING: rails-settings-cached 2.x has redesigned the API, the new version will compatible with the stored setting values by an older version. When you want to upgrade 2.x, you must read the README again, and follow guides to change your Setting model. 0.x stable branch: https://github.com/huacnlee/rails-settings-cached/tree/0.x
For new project / new user of rails-settings-cached. The ActiveRecord::AttributeMethods::Serialization is best choice.
This is reason of why rails-settings-cached 2.x removed Scoped Settings feature.
For example:
We wants a preferences setting for user.
class User < ActiveRecord::Base
serialize :preferences
end
@user = User.new
@user.preferences[:receive_emails] = true
@user.preferences[:public_email] = true
@user.save
Use cases:
- ruby-china/homeland - master
- forem/forem - 2.x
- siwapp/siwapp - 2.x
- aidewoode/black_candy - 2.x
- thebluedoc/bluedoc - 2.x
- tootsuite/mastodon - 0.6.x
- helpyio/helpy - 0.5.x
And more than 1K repositories used.