Top Related Projects
Quick Overview
Rails Settings Cached is a Ruby gem that provides a simple way to add application-wide settings to your Ruby on Rails projects. It offers a convenient interface for storing and retrieving settings, with built-in caching for improved performance.
Pros
- Easy integration with Ruby on Rails applications
- Built-in caching mechanism for faster access to settings
- Supports both global and scoped settings
- Allows for default values and type casting
Cons
- Limited to Ruby on Rails applications
- May require additional configuration for complex use cases
- Potential for cache inconsistencies if not managed properly
- Lacks advanced features like versioning or audit trails
Code Examples
Setting and retrieving a global setting:
Settings.site_name = "My Awesome Site"
puts Settings.site_name # Output: "My Awesome Site"
Using scoped settings:
Settings.user.theme = "dark"
puts Settings.user.theme # Output: "dark"
Defining default values:
class Settings < RailsSettings::Base
field :app_name, default: "My App", type: :string
field :max_users, default: 100, type: :integer
end
puts Settings.app_name # Output: "My App"
puts Settings.max_users # Output: 100
Getting Started
- Add the gem to your Gemfile:
gem 'rails-settings-cached'
- Run bundle install:
bundle install
- Generate the settings migration:
rails g rails_settings:migration
- Run the migration:
rails db:migrate
- Create a
config/initializers/settings.rb
file:
class Settings < RailsSettings::Base
cache_prefix { "v1" }
end
- Start using settings in your application:
Settings.some_setting = "Some value"
puts Settings.some_setting
Competitor Comparisons
Simple Rails app configuration
Pros of Figaro
- Focuses on environment-specific configuration and sensitive data management
- Provides a simple way to set and access environment variables
- Integrates well with various deployment platforms (e.g., Heroku)
Cons of Figaro
- Limited to managing environment variables only
- Doesn't provide caching mechanisms for settings
- Less suitable for dynamic runtime configuration changes
Code Comparison
Figaro:
# config/application.yml
GMAIL_USERNAME: "user@example.com"
GMAIL_PASSWORD: "password"
# Usage
Figaro.env.gmail_username
Rails Settings Cached:
# config/initializers/settings.rb
Setting.save_default(:gmail_username, "user@example.com")
Setting.save_default(:gmail_password, "password")
# Usage
Setting.gmail_username
Summary
Figaro is primarily focused on managing environment variables and sensitive data, making it ideal for configuration across different environments. It's particularly useful for deployment platforms like Heroku. However, it lacks caching mechanisms and is less suitable for dynamic runtime changes.
Rails Settings Cached, on the other hand, provides a more comprehensive solution for managing application settings. It offers caching capabilities and allows for dynamic updates during runtime. This makes it more versatile for complex applications that require frequent setting changes or performance optimization.
The choice between these two depends on the specific needs of your project, with Figaro being simpler for environment-specific configs and Rails Settings Cached offering more advanced features for general application settings management.
A Ruby gem to load environment variables from `.env`.
Pros of dotenv
- Simple and lightweight, focusing solely on loading environment variables
- Language-agnostic, can be used with various programming languages and frameworks
- Widely adopted and well-maintained, with a large community
Cons of dotenv
- Limited to managing environment variables, lacks advanced features for settings management
- Doesn't provide caching mechanisms, which may impact performance for frequently accessed variables
- No built-in support for different environments (e.g., development, production)
Code Comparison
dotenv:
require 'dotenv'
Dotenv.load
puts ENV['DATABASE_URL']
rails-settings-cached:
Setting.cache_prefix = 'v1'
Setting.database_url = 'postgres://localhost/myapp'
puts Setting.database_url
Key Differences
rails-settings-cached offers more advanced features for managing application settings, including:
- Caching mechanism for improved performance
- Support for different data types (not just strings)
- Ability to change settings at runtime
- Seamless integration with Rails applications
dotenv, on the other hand, is simpler and more focused on managing environment variables across different platforms and languages.
Choose rails-settings-cached for more comprehensive settings management in Rails applications, or dotenv for a lightweight solution to handle environment variables in various environments and languages.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Rails Settings Cached
The best solution for store global settings in Rails applications.
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 application.
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" }
scope :application do
field :app_name, default: "Rails Settings", validates: { presence: true, length: { in: 2..20 } }
field :host, default: "http://example.com", readonly: true
field :default_locale, default: "zh-CN", validates: { presence: true, inclusion: { in: %w[zh-CN en jp] } }, option_values: %w[en zh-CN jp], help_text: "Bla bla ..."
field :admin_emails, type: :array, default: %w[admin@rubyonrails.org]
# lambda default value
field :welcome_message, type: :string, default: -> { "welcome to #{self.app_name}" }, validates: { length: { maximum: 255 } }
# Override array separator, default: /[\n,]/ split with \n or comma.
field :tips, type: :array, separator: /[\n]+/
end
scope :limits do
field :user_limits, type: :integer, default: 20
field :exchange_rate, type: :float, default: 0.123
field :captcha_enable, type: :boolean, default: true
end
field :notification_options, type: :hash, default: {
send_all: true,
logging: true,
sender_email: "foo@bar.com"
}
field :readonly_item, type: :integer, default: 100, readonly: true
end
You must use the field
method to statement the setting keys, otherwise you can't use it.
The scope
method allows you to group the keys for admin UI.
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
Setting.editable_keys
=> ["app_name", "default_locale"]
# Get readonly keys
Setting.readonly_keys
=> ["host", "readonly_item"]
# Get field
Setting.get_field("host")
=> { scope: :application, key: "host", type: :string, default: "http://example.com", readonly: true }
Setting.get_field("app_name")
=> { scope: :application, key: "app_name", type: :string, default: "Rails Settings", readonly: false }
Setting.get_field(:user_limits)
=> { scope: :limits, key: "user_limits", type: :integer, default: 20, readonly: false }
# Get field options
Setting.get_field("default_locale")[:options]
=> { option_values: %w[en zh-CN jp], help_text: "Bla bla ..." }
Custom type for setting
Since: 2.9.0
You can write your custom field type by under RailsSettings::Fields
module.
For example
module RailsSettings
module Fields
class YesNo < ::RailsSettings::Fields::Base
def serialize(value)
case value
when true then "YES"
when false then "NO"
else raise StandardError, 'invalid value'
end
end
def deserialize(value)
case value
when "YES" then true
when "NO" then false
else nil
end
end
end
end
end
Now you can use yes_no
type in you setting:
class Setting
field :custom_item, type: :yes_no, default: 'YES'
end
irb> Setting.custom_item = 'YES'
irb> Setting.custom_item
true
irb> Setting.custom_item = 'NO'
irb> Setting.custom_item
false
Get All defined fields
version 2.7.0+
You can use defined_fields
method to get all defined fields in Setting.
# Get editable fields and group by scope
editable_fields = Setting.defined_fields
.select { |field| !field[:readonly] }
.group_by { |field| field[:scope] }
Validations
You can use validates
options to special the Rails Validation for fields.
class Setting < RailsSettings::Base
# cache_prefix { "v1" }
field :app_name, default: "Rails Settings", validates: { presence: true, length: { in: 2..20 } }
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]" } }
end
Now validate will work on record save:
irb> Setting.app_name = ""
ActiveRecord::RecordInvalid: (Validation failed: App name can't be blank)
irb> Setting.app_name = "Rails Settings"
"Rails Settings"
irb> Setting.default_locale = "zh-TW"
ActiveRecord::RecordInvalid: (Validation failed: Default locale is not included in [zh-CN, en, jp])
irb> Setting.default_locale = "en"
"en"
Validate by save
/ valid?
method:
setting = Setting.find_or_initialize_by(var: :app_name)
setting.value = ""
setting.valid?
# => false
setting.errors.full_messages
# => ["App name can't be blank", "App name too short (minimum is 2 characters)"]
setting = Setting.find_or_initialize_by(var: :default_locale)
setting.value = "zh-TW"
setting.save
# => false
setting.errors.full_messages
# => ["Default locale is not included in [zh-CN, en, jp]"]
setting.value = "en"
setting.valid?
# => true
Use Setting in Rails initializing:
In version 2.3+
you can 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 before Rails initialize:
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
config/environments/production.rb
# You must require_relative directly in Rails 6.1+ in config/environments/production.rb
require_relative "../../app/models/setting"
Rails.application.configure do
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = Setting.mailer_options.deep_symbolize_keys
end
TIP: You also can follow this file to rewrite ActionMailer's mail
method for configuration Mail options from Setting after Rails booted.
https://github.com/ruby-china/homeland/blob/main/app/mailers/application_mailer.rb#L19
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 ActiveSupport::CurrentAttributes 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
def create
@errors = ActiveModel::Errors.new
setting_params.keys.each do |key|
next if setting_params[key].nil?
setting = Setting.new(var: key)
setting.value = setting_params[key].strip
unless setting.valid?
@errors.merge!(setting.errors)
end
end
if @errors.any?
render :new
end
setting_params.keys.each do |key|
Setting.send("#{key}=", setting_params[key].strip) unless setting_params[key].nil?
end
redirect_to admin_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| %>
<% if @errors.any? %>
<div class="alert alert-block alert-danger">
<ul>
<% @errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<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 %>
Special Cache Storage
You can use cache_store
to change cache storage, default is Rails.cache
.
Add config/initializers/rails_settings.rb
RailsSettings.configure do
self.cache_storage = ActiveSupport::Cache::RedisCacheStore.new(url: "redis://localhost:6379")
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
- huacnlee/bluedoc - 2.x
- getzealot/zealot - 2.x
- kaishuu0123/rebacklogs - 2.x
- texterify/texterify - 2.x
- mastodon/mastodon - 0.6.x
- helpyio/helpy - 0.5.x
- maybe-finance/maybe - 2.x
And more than 1K repositories used.
Top Related Projects
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot