Code Monkey home page Code Monkey logo

rails-settings-cached's Introduction

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.

Gem Version build

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[[email protected]]

    # 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: "[email protected]"
  }

  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
["[email protected]"]
irb > Setting.admin_emails = %w[[email protected] [email protected]]
irb > Setting.admin_emails
["[email protected]", "[email protected]"]
irb > Setting.admin_emails = "[email protected],[email protected]\n[email protected]"
irb > Setting.admin_emails
["[email protected]", "[email protected]", "[email protected]"]

irb > Setting.notification_options
{
  send_all: true,
  logging: true,
  sender_email: "[email protected]"
}
irb > Setting.notification_options = {
  sender_email: "[email protected]"
}
irb > Setting.notification_options
{
  sender_email: "[email protected]"
}

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:

And more than 1K repositories used.

rails-settings-cached's People

Contributors

accessd avatar adambutler avatar alexanderadam avatar alexjwayne avatar alistairholt avatar amanfrinati avatar berkos avatar brandoncordell avatar brentkearney avatar dangerous avatar dependabot[bot] avatar fwolfst avatar hovsater avatar huacnlee avatar huobazi avatar javierav avatar jehops avatar justin-natance avatar justin808 avatar kennethteh90 avatar kiela avatar ledermann avatar merqlove avatar mgrachev avatar miks avatar mlandauer avatar ncreuschling avatar pmq20 avatar sangnguyen1001 avatar tsipiniuk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rails-settings-cached's Issues

uninitialized constant RailsSettings

Console works:

Loading development environment (Rails 3.1.1)

> > Setting.background_color
> > => "#ffd600"
> > 
> > ```
> > ```

But erb doesn't.  For example this:
`the color is <%= Setting.background_color %>`
gives 
`uninitialized constant RailsSettings`

NoMethodError: undefined method `scope_for_create' for {}:ActiveSupport::HashWithIndifferentAccess

I get this error when I use rails-settings-cached 0.3.2 with Rails 4.1.

The root cause is that Settings.all returns an instance of ActiveSupport::HashWithIndifferentAccess rather than ActiveRecord::Relation, and Rails now expects .all to return a relation.

Here's a backtrace:

     NoMethodError:
       undefined method `scope_for_create' for {}:ActiveSupport::HashWithIndifferentAccess
     # /Users/afn/.rvm/gems/ruby-2.1.0/gems/activerecord-4.1.0.beta1/lib/active_record/scoping/named.rb:39:in `scope_attributes'
     # /Users/afn/.rvm/gems/ruby-2.1.0/gems/activerecord-4.1.0.beta1/lib/active_record/scoping.rb:25:in `populate_with_current_scope_attributes'
     # /Users/afn/.rvm/gems/ruby-2.1.0/gems/activerecord-4.1.0.beta1/lib/active_record/core.rb:177:in `initialize'
     # /Users/afn/.rvm/gems/ruby-2.1.0/gems/activerecord-4.1.0.beta1/lib/active_record/inheritance.rb:27:in `new'
     # /Users/afn/.rvm/gems/ruby-2.1.0/gems/activerecord-4.1.0.beta1/lib/active_record/inheritance.rb:27:in `new'
     # /Users/afn/.rvm/gems/ruby-2.1.0/gems/activerecord-4.1.0.beta1/lib/active_record/relation.rb:108:in `block in new'
     # /Users/afn/.rvm/gems/ruby-2.1.0/gems/activerecord-4.1.0.beta1/lib/active_record/relation.rb:285:in `scoping'
     # /Users/afn/.rvm/gems/ruby-2.1.0/gems/activerecord-4.1.0.beta1/lib/active_record/relation.rb:108:in `new'
     # /Users/afn/.rvm/gems/ruby-2.1.0/gems/rails-settings-cached-0.3.2/lib/rails-settings/settings.rb:79:in `[]='
     # /Users/afn/.rvm/gems/ruby-2.1.0/gems/rails-settings-cached-0.3.2/lib/rails-settings/settings.rb:25:in `rescue in method_missing'
     # /Users/afn/.rvm/gems/ruby-2.1.0/gems/rails-settings-cached-0.3.2/lib/rails-settings/settings.rb:18:in `method_missing'

For now I've worked around it by monkey-patching HashWithIndifferent access thusly, but clearly this isn't the right approach:

module ActiveSupport
  class HashWithIndifferentAccess
    def scope_for_create
      {}
    end
  end
end

I think the proper solution is to change the definition of self.all to return something that more closely resembles an ActiveRecord relation.

Editing with active admin

First of all, I know this issue could not belong here. And thanks for this gem, seems exactly what I need.

I was thinking about having a nice interface to edit settings, so I thought in active_admin as it is easy to use and set.

Settings tab appears in active admin, but when I click in the tab I get:

can't convert nil into String
Extracted source (around line #1):
1: insert_tag renderer_for(:new)

Anyone could give me some advice on this?

Thanks.

How does the caching work?

Hi,

Could anyone explain how do the settings get cached?

The reason I am asking is that it seems to me that, when I change a specific settings value, the change does not seem to be picked up by my background worker (sidekiq).

It's only picked up after the server is restarted.

Thanks

Rails4 Field 'var' doesn't have a default value

4] pry(main)> smart_customer.settings.color = :red
  RailsSettings::ScopedSettings Load (0.4ms)  SELECT `settings`.* FROM `settings` WHERE `settings`.`thing_type` = 'SmartCustomer' AND `settings`.`thing_id` = 1 AND `settings`.`var` = 'color' ORDER BY `settings`.`id` ASC LIMIT 1
WARNING: Can't mass-assign protected attributes for RailsSettings::ScopedSettings: var

   (0.2ms)  BEGIN
  SQL (0.5ms)  INSERT INTO `settings` (`created_at`, `thing_id`, `thing_type`, `updated_at`, `value`) VALUES ('2013-11-15 14:53:13', 1, 'SmartCustomer', '2013-11-15 14:53:13', '--- :red\n...\n')
Mysql2::Error: Field 'var' doesn't have a default value: INSERT INTO `settings` (`created_at`, `thing_id`, `thing_type`, `updated_at`, `value`) VALUES ('2013-11-15 14:53:13', 1, 'SmartCustomer', '2013-11-15 14:53:13', '--- :red\n...\n')
   (0.2ms)  ROLLBACK
ActiveRecord::StatementInvalid: Mysql2::Error: Field 'var' doesn't have a default value: INSERT INTO `settings` (`created_at`, `thing_id`, `thing_type`, `updated_at`, `value`) VALUES ('2013-11-15 14:53:13', 1, 'SmartCustomer', '2013-11-15 14:53:13', '--- :red\n...\n')

Bug/Howto using table_name or table_name_prefix ?

Hello,

For some reason I had to rename the db table from 'settings' to 'db_settings', then I tried to use self.table_name = 'db_settings' or self.table_name_prefix = 'db_' in my model, but it doesn't work, any idea pls ?

app/models/db_settings.rb :

class DbSettings < RailsSettings::CachedSettings
  #self.table_name = 'db_settings'
  self.table_name_prefix = 'db_'
  attr_accessible :var, :value
  validates_presence_of :var, :value
end

rails console :

[19] pry(main)> DbSettings['foo'] = 'bar'
  DbSettings Load (1.5ms)  SELECT "db_settings".* FROM "db_settings" WHERE "db_settings"."thing_type" IS NULL AND "db_settings"."thing_id" IS NULL AND "db_settings"."var" = 'foo' LIMIT 1
ActiveRecord::StatementInvalid: PGError: ERROR:  relation "settings" does not exist
LINE 5:              WHERE a.attrelid = '"settings"'::regclass
                                        ^
:             SELECT a.attname, format_type(a.atttypid, a.atttypmod),
                     pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
              FROM pg_attribute a LEFT JOIN pg_attrdef d
                ON a.attrelid = d.adrelid AND a.attnum = d.adnum
             WHERE a.attrelid = '"settings"'::regclass
               AND a.attnum > 0 AND NOT a.attisdropped
             ORDER BY a.attnum

Can not migrate db

When deploy project I catch this error:

rake db:migrate PG::UndefinedTable: ERROR: relation "settings" does not exist LINE 5: WHERE a.attrelid = '"settings"'::regclass

Settings of false value bug

class Setting < RailsSettings::CachedSettings
end

Setting.defaults['foo'] = true
Setting['foo'] = false
Setting['foo'] # still return true value

# if cached setting is not used, problem is gone.
class Setting < RailsSettings::Settings
end

Default settings returned as hash, persistent settings are strings

When you use Setting.get_all you get a hash of settings. Default settings are returned as:

{
  foo: { bar: 'foo' }
}

Persistent settings are returned as:

{
  'foo.bar': 'foo'
}

This will return an inconsistent settings hash. I think one of these formats should be chosen, probably the string version as the hash would be too backwards incompatible.

Controller #Update Method

Hey,

Amazing work you got going here !

I'm struck at a point which is not developed in the Readme but I am sure would interest more than just me.

How do you deal with updating the settings in the SettingsController once you have gathered your keys-values in a params hash or similar ?

class SettingsController < ApplicationController
  def index
    # to get all items for render list
    @settings = Setting.unscoped
  end

  def edit
    @setting = Setting.unscoped.find(params[:id])
  end

  def update
    # How to go from this ?
    Setting.foo = 'bar'
    # To :
    params.each do |key,value|
      Setting.send(key) = value # Obviously wrong
    end
  end
end

Keep up the good work !

Apartment

Hi,

I am using Apartment gem in my app.
I can't figure out how to properly set up rails-settings-gem to work with Apartment.

Does anyone have any experience with it?
Should I put settings model in excluded models or not?

Thx

Update to latest version messed up things

Hi,

I am not sure if I am doing something wrong, but today, after i have updated a gem to the latest version, i am getting bunch of weird behavior.

First i had problems with the initializer, which seems to be replaced with YML file.
I've migrated all the settings done in initilizer to te settings yaml, with a normal yml structure (before it was just flat...).

Now some settings work, but some have weird behaviour, like the value is not read properly.
For example, when i change something in the GUI, it should be persisted in the DB. And in the GUI i can see a proper value. In console however (and controller where i actually do this) current_user.setting.get_all seems to be fetching YML values - which is a bummer - I know this was pretty much working before the update.

Also, I am noticing, that values sometimes update, but sometimes just don't.
Very weird.

Is there some kind of migration doc that i am not aware of?
Should i do something else that i have missed somewhere?

I am using Rails 4.2.5 with redis cache store.

Problem with specs due to TX and hook not running

Thanks for the Gem!

We're using 0.5.2 and Rails 4.2.

And we've got got that looks like this:

Settings.foobar = 1
MyModel.transaction do
  Settings.foobar = 123
  puts "Settings.foobar is #{Settings.foobar}"
end

This will print 1, rather than 123 because of this:

https://github.com/huacnlee/rails-settings-cached/blob/master/lib%2Frails-settings-cached.rb#L8

We're waiting until the TX commits before clearing the cache.

Why not at least remove the cache key?

I'll create a PR and show the code.

There's a slight timing issue in that another thread can fetch the cache value and fill in the cache again with the old value, but once the TX commits for the new cache value, the cache is again cleared.

Also, why is the whole cache cleared and not just the key changed?

Can't mass-assign protected attributes for RailsSettings::ScopedSettings: var

Hello,

I recently upgraded a rails app using rails-settings-cached from rails 3.2.16 to Rails 4.0.9.

The rails-settings-cached is used to save user specific settings and there's a callback 'after_create' to set the right values.
However, after the upgrade, I keep receiving the following error triggered from the callback:

ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes for RailsSettings::ScopedSettings: var

The corresponding line in the code is the following:

user.settings.sort_contacts = "first_name"

I am using rails-settings-cached version 0.3.2.

Is there anything I should be looking at to make it work properly? Thanks

Alternative ORM Support

Wasn't able to use this gem with mongoid. It would be nice if I didn't need ActiveRecord.

默认值存储为正则表达式,编辑页面的时候出错 Unknown default value type Regexp

class Setting < RailsSettings::CachedSettings
defaults[:current_sms_verify_tpl_id] = 1
defaults[:mobile_regex_format] = /\A1[3|4|5|8][0-9]\d{8}\z/
end

Unknown default value type Regexp

Extracted source (around line #44):
42
43
44
45
46
47

  default_setting_value_type = RailsSettingsUi.settings_klass.defaults[name.to_sym].class
  unless VALUE_TYPES_MAP.keys.include?(default_setting_value_type)
    raise RailsSettingsUi::UnknownDefaultValueType, "Unknown default value type #{default_setting_value_type}"
  end

  setting_value_type_class = VALUE_TYPES_MAP[default_setting_value_type]

Force database access - Heroku

I have deployed my application on Heroku and the caching behavior seems weird... It seems that when I change one of the settings dynamically, via a web interface, the other processes, such as workers and schedulers (and even other web dynos) don't notice the change and keep getting the old cached value.

Is there a way to force the value to be read via a database access? I can't restart my processes every time I make a change...

Setting.save_default does not work when defaults[] is used in the model

When defaults are placed in the Setting model...
class Setting < RailsSettings::CachedSettings
defaults[:test] = "Test Setting"
end

a call to...
Setting.save_default(:test, "A new Setting") returns nil and does not save the setting to the database.

Suggest modifying the software so save_default overrides and creates the database record.
thanks,
Don

use mysql 0.4 problem

use mysql2 0.4.0 sidekiq can't start, switch mysql 0.3.20 no problem.

(called from <class:CachedSettings> at /data/spole/www/shared/bundle/ruby/2.2.0/gems/rails-settings-cached-0.4.2/lib/rails-settings/cached_settings.rb:8)
/data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/connection_specification.rb:177:in `rescue in spec': Specified 'mysql2' for database adapter, but the gem is not loaded. Add `gem 'mysql2'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord). (Gem::LoadError)
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_adapters/connection_specification.rb:174:in `spec'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.4/lib/active_record/connection_handling.rb:50:in `establish_connection'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.4/lib/active_record/railtie.rb:120:in `block (2 levels) in <class:Railtie>'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/lazy_load_hooks.rb:38:in `instance_eval'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/lazy_load_hooks.rb:38:in `execute_hook'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/lazy_load_hooks.rb:28:in `block in on_load'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/lazy_load_hooks.rb:27:in `each'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/lazy_load_hooks.rb:27:in `on_load'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activerecord-4.2.4/lib/active_record/railtie.rb:116:in `block in <class:Railtie>'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:30:in `instance_exec'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:30:in `run'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:55:in `block in run_initializers'
        from /data/spole/.rbenv/versions/2.2.3/lib/ruby/2.2.0/tsort.rb:226:in `block in tsort_each'
        from /data/spole/.rbenv/versions/2.2.3/lib/ruby/2.2.0/tsort.rb:348:in `block (2 levels) in each_strongly_connected_component'
        from /data/spole/.rbenv/versions/2.2.3/lib/ruby/2.2.0/tsort.rb:429:in `each_strongly_connected_component_from'
        from /data/spole/.rbenv/versions/2.2.3/lib/ruby/2.2.0/tsort.rb:347:in `block in each_strongly_connected_component'
        from /data/spole/.rbenv/versions/2.2.3/lib/ruby/2.2.0/tsort.rb:345:in `each'
        from /data/spole/.rbenv/versions/2.2.3/lib/ruby/2.2.0/tsort.rb:345:in `call'
        from /data/spole/.rbenv/versions/2.2.3/lib/ruby/2.2.0/tsort.rb:345:in `each_strongly_connected_component'
        from /data/spole/.rbenv/versions/2.2.3/lib/ruby/2.2.0/tsort.rb:224:in `tsort_each'
        from /data/spole/.rbenv/versions/2.2.3/lib/ruby/2.2.0/tsort.rb:203:in `tsort_each'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/initializable.rb:54:in `run_initializers'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/application.rb:352:in `initialize!'
        from /data/spole/www/releases/16/config/environment.rb:5:in `<top (required)>'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `require'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `block in require'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:240:in `load_dependency'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.4/lib/active_support/dependencies.rb:274:in `require'
        from /data/spole/www/shared/bundle/ruby/2.2.0/gems/sidekiq-3.5.0/lib/sidekiq/cli.rb:247:in `boot_system'
        from /data/spole/www/shared/bundle/ruby/2.2.0/gems/sidekiq-3.5.0/lib/sidekiq/cli.rb:50:in `run'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/gems/sidekiq-3.5.0/bin/sidekiq:13:in `<top (required)>'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/bin/sidekiq:23:in `load'
        from /data/spole/www/releases/16/vendor/bundle/ruby/2.2.0/bin/sidekiq:23:in `<main>'

Read from DB directly

For example, I want to read key from DB directly, not from cache. Is it possible?

Same cache between instances

Actually, I want to change setting values in test environment. When I simple set it at beginning of my test, it will override the value of development instance.

I can mock the method of model, but I'm using namespaces:

Setting['comment.rpp']

so I'm not sure, what method should I stub. []? Anyway, simply set value at beginning is better and more clean than stubbing methods

How do you think, is this problem of this great gem?

Releases

I think the releases must be in github "release" section too. Most of the users check if the repo is active by looking at releases page and release dates in github. This repo has releases in rubygems.org but not in github.

Direct write default value into database

I currently, the Setting.defaults[:foo] method just store in a variable, when I need implement a admin interface to manage the setting keys, it can not be list the default keys with access Setting.all

Cache not updated after changing the value?

Hi, I updated my project from Rails 3.2.x to Rails 4.2.5. One of my unit test failed because there is something wrong with the settings cache.

test "should return 503" do
    puts Setting.amazon_on # it's true
    Setting.amazon_on = false
    puts Setting.amazon_on # it's true
    get :show, {:uid => 'uid', :content => 1} # my controller read true
    assert @response.status == 503
end

I'm using version 0.5.3 (previously 0.2.4)

Stack Level Too Deep

When I start up my rails application I get this error message:

/usr/local/rvm/gems/ree-1.8.7-2011.03@voice_manager/gems/activerecord-3.1.0/lib/active_record/dynamic_scope_match.rb:12:in 'match': stack level too deep (SystemStackError)
from /usr/local/rvm/gems/ree-1.8.7-2011.03@voice_manager/gems/activerecord-3.1.0/lib/active_record/base.rb:1061:in 'method_missing'
from /usr/local/rvm/gems/ree-1.8.7-2011.03@voice_manager/gems/rails-settings-cached-0.1.2/lib/rails-settings/settings.rb:20:in 'method_missing'
from /usr/local/rvm/gems/ree-1.8.7-2011.03@voice_manager/gems/rails-settings-cached-0.1.2/lib/rails-settings/settings.rb:108:in 'thing_scoped'
from /usr/local/rvm/gems/ree-1.8.7-2011.03@voice_manager/gems/rails-settings-cached-0.1.2/lib/rails-settings/settings.rb:94:in 'object'
from /usr/local/rvm/gems/ree-1.8.7-2011.03@voice_manager/gems/rails-settings-cached-0.1.2/lib/rails-settings/settings.rb:61:in '[]'
from /usr/local/rvm/gems/ree-1.8.7-2011.03@voice_manager/gems/rails-settings-cached-0.1.2/lib/rails-settings/cached_settings.rb:14:in '[]'
from /usr/local/rvm/gems/ree-1.8.7-2011.03@voice_manager/gems/activesupport-3.1.0/lib/active_support/cache.rb:297:in 'fetch'
from /usr/local/rvm/gems/ree-1.8.7-2011.03@voice_manager/gems/activesupport-3.1.0/lib/active_support/cache.rb:520:in 'instrument'
... 8824 levels...
from /usr/local/rvm/gems/ree-1.8.7-2011.03@voice_manager/gems/rack-1.3.5/lib/rack/builder.rb:51:in 'instance_eval'
from /usr/local/rvm/gems/ree-1.8.7-2011.03@voice_manager/gems/rack-1.3.5/lib/rack/builder.rb:51:in 'initialize'
from /usr/local/sipfish/webui/config.ru:1 in 'new'
from /usr/local/sipfish/webui/config.ru:1

I went into the method_missing definition in settings.rb and put a line to puts("method is #{method}") and the offending call is scoped_by_thing_type_and_thing_id. I looked through the source and could not find this class method defined anywhere, though it is called from two places (settings.rb:107 and scoped_settings.rb:9).

Version info:
Rails 3.1.0
Ruby Enterprise Edition (1.8.7)
ActiveRecord 3.1.0
rails-settings-cached 0.1.2

Rendering form for all settings

Can someone provide some instructions how to make a form for all settings.
I need one view to edit all my settings. Thnks!

Cache expiration

It would be nice to allow cache expiration.
One possible use case is when another system changes the setting value and we want our system to be aware of it after some time.

Gem not found on Rubygems.org

After running a bundle command, I receive the error:

Could not find rails-settings-cached-0.2.4.gem for installation

I added the Github repo as the source for the gem in my Gemfile, but it looks like that version is for Rails 4.

Question: value stored in DB with dashes and dots

Hi, I'm wondering if this is the expected behavior, and why - I'll create a setting:

>> Setting.slinky = 0
>> Setting.slinky
>> 0

But when I view the data in the database its stored as:

--- 0
...

Main reason I'm asking is because I'm providing an edit form for admins and the dashes and dots are pre-populated in the form so I need to figure out why to avoid any issues. Thanks.

Possible regression in 0.4.5 - updates not reflected on next read

I believe I am seeing a regression in 0.4.5. The following code works as expected with 0.4.4, but does not work as expected with 0.4.5:

p Setting.test# expect nil
Setting.test= 'foo'
p Setting.test# expect 'foo', get nil

It appears that writes do not invalidate or update the cache, whereas in 0.4.4 they did.

Understanding how caching works

Sorry I am opening this ticket, but I would really like to understand how it all fits together.
I am having major problems and I have currently no idea why it is happening.

In development environment everything works as expected.
In production, however, i am getting really weird behavior.

I have a settings page where one can change the value of the setting (check boxes).
When I hit update, than weird things are happening; when returned back to the page, values could be wrong, sometimes they are correct. Hit refresh few times and again values can be correct or not.

It is like the values are read from cache/db, updated - i can't really pinpoint why such a strange behavior. Same thing is happening for some DIVs i can show/hide via settings. When hitting refresh, sometimes they open and sometimes the are closed (no matter what i set as a setting).

So, I would like to understand when DB is hit, when Cache is read and when the cache is expired?

Maybe it could be something with the stack?
I am using nginx/unicorn/redis.

Thank you very much!

Test Database?

Hey there,

Seems as though when I run tests involving this gem (in Rspec) it is using the development database, as opposed to the test database. Am I doing something wrong?

Default Setting doesn't work

I follow README create a init file .

config/initializers/default_settings.rb

Setting.defaults[:dollor_rate] = "6.3600"
Setting.defaults[:gia_price] = "300"
Setting.defaults[:inscription_price] = "500"

but when I go to console

 pry(main)> Setting.gia_price
=> nil
[2] pry(main)> Setting.defaults
=> {"dollor_rate"=>"6.3600", "gia_price"=>"300", "inscription_price"=>"500"}
[3] pry(main)> Setting[:gia_price]
=> nil
[5] pry(main)> Setting.defaults
=> {"dollor_rate"=>"6.3600", "gia_price"=>"300", "inscription_price"=>"500"}
[6] pry(main)> Setting.all
  Setting Load (0.4ms)  SELECT var, value FROM `settings` WHERE `settings`.`thing_type` IS NULL AND `settings`.`thing_id` IS NULL
=> {"dollor_rate"=>"6.36566"}

Default setting doesn't work. I am using Rails3.2.2.

Strict dependency on 'Rails'

Sometimes it would be useful to have it working on a non-rails project. The Rails gem dependency makes it not possible. I noticed there are calls for the Rails.cache objects. Isn't there a way of creating specific depencencies for the Rails.cache classes? eg: require 'rails/cache'. In this fashion one could add other require statments like 'activesupport/all' and 'activerecord' to make it work on a plain ruby+pg setup.

Nice work, by the way. Thanks for this valuable gem.

Could not find generator 'settings'

I've added gem to Gemfile, made bundle install with no problems. Then I tried to generate model, but after 'rails g settings Packet' i got info that Could not find generator 'settings'.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.