Giter Club home page Giter Club logo

better_settings's Introduction

Better Settings

Build Status Maintainability Test Coverage Gem Version License

A robust settings library for Ruby. Access your settings by calling methods on a safe immutable object.

Features ⚡️

  • 🚀 Light and Performant: settings are eagerly loaded, no method_missing tricks, no dependencies.
  • 💬 Useful Error Messages: when trying to access a setting that does not exist.
  • 💎 Immutability: once created settings can't be modified.
  • 🗂 Multiple Files: useful to create multiple environment-specific source files.
  • No Optional Setings: since it encourages unsafe access patterns.

You can read more about it in the blog announcement.

Installation 💿

Add this line to your application's Gemfile:

gem 'better_settings'

And then execute:

$ bundle

Or install it yourself as:

$ gem install better_settings

Usage 🚀

1. Define a class

Create a class in your application that extends BetterSettings:

# app/models/settings.rb
class Settings < BetterSettings
  source Rails.root.join('config', 'application.yml'), namespace: Rails.env
end

We use Rails.root in this example to obtain an absolute path to a plain YML file, but when using other Ruby frameworks you can use File.expand_path with __dir__ instead.

Also, we specified a namespace with the current environment. You can provide any value that corresponds to a key in the YAML file that you want to use. This allows to target different environments with the same file.

2. Create your settings

Now, create a YAML file that contains all the possible namespaces:

# config/application.yml
defaults: &defaults
  port: 80
  mailer:
    root: www.example.com
  dynamic: <%= "Did you know you can use ERB inside the YML file? Env is #{ Rails.env }." %>

development:
  <<: *defaults
  port: 3000

test:
  <<: *defaults

production:
  <<: *defaults

The defaults group in this example won't be used directly, we are using YAML's syntax to reuse those values when we use <<: *defaults, allowing us to share these values across environments.

3. Access your settings

You can use these settings anywhere, for example in a model:

class Post < ActiveRecord::Base
  self.per_page = Settings.pagination.posts_per_page
end

or in the console:

>> Rails.env
=> "development"

>> Settings.mailer
=> "#<Settings ... >"

>> Settings.mailer.root
=> "www.example.com

>> Settings.port
=> 3000

>> Settings.dynamic
=> "Did you know you can use ERB inside the YML file? Env is development."

Advanced Setup ⚙

You can create as many setting classes as you need, and name them in different ways, and read from as many files as necessary (nested keys will be merged).

The way I like to use it, is by reading a few optional files for the development and test environments, which allows each developer to override some settings in their own local environment (and git ignoring development.yml and test.yml).

# app/models/settings.rb
class Settings < BetterSettings
  source Rails.root.join('config/application.yml'), namespace: Rails.env
  source Rails.root.join('config/development.yml'), namespace: Rails.env, optional: true if Rails.env.development?
  source Rails.root.join('config/test.yml'), namespace: Rails.env, optional: true if Rails.env.test?
end

Then application.yml looks like this:

# application.yml
defaults: &defaults
  auto_logout: false
  secret_key_base: 'fake_secret_key_base'

server_defaults: &server_defaults
  <<: *defaults
  auto_logout: true
  secret_key: <%= ENV['SECRET_KEY'] %>

development:
  <<: *defaults
  host: 'localhost'

test:
  <<: *defaults
  host: '127.0.0.1'

staging:
  <<: *server_defaults
  host: 'staging.example.com'

production:
  <<: *server_defaults
  host: 'example.com'

A developer might want to override some settings by defining a development.yml such as:

development:
  auto_logout: true

The main advantage is that those changes won't be tracked in source control 😃

better_settings's People

Contributors

elmassimo avatar pablomdiaz avatar

Stargazers

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

Watchers

 avatar  avatar  avatar

Forkers

mochetts

better_settings's Issues

Rails 7 Won't allow Settings inside initilaizers

Description 📖

When upgrading to Rails 7 from Rails 6.1 I am unable to load Settings in initializers.

Reproduction 🐞

bundle exec rake zeitwerk:check 
rake aborted!
NameError: uninitialized constant Settings
Did you mean?  String
/core/config/initializers/sidekiq.rb:10:in `<main>'
# config/initilizers/sidekiq.rb
...
redis_host_string = "#{Settings.redis.scheme}://#{Settings.redis.host}:#{Settings.redis.port}/#{Settings.redis.sidekiq_db}"

Logs 📜

Error output or similar when the error occurs:

Output
bundle exec rake zeitwerk:check                                                                        ─╯
rake aborted!
NameError: uninitialized constant Settings
Did you mean?  String
/Users/tom/Workspace/core/config/initializers/sidekiq.rb:10:in `<main>'
/Users/tom/Workspace/core/config/environment.rb:5:in `<main>'
/Users/tom/.rbenv/versions/3.0.3/bin/bundle:23:in `load'
/Users/tom/.rbenv/versions/3.0.3/bin/bundle:23:in `<main>'
Tasks: TOP => zeitwerk:check => environment
(See full trace by running task with --trace)

Screenshots 📷

Provide console or browser screenshots of the problem.

1.0.2 breaks ruby compatibility <= 3.1

If this gem is going to be ruby 3.1 only that should not be released as part of a patch release. Perhaps releasing it as 2.0.0 would be better to denote the scope of the breaking changes?

Ruby 3.1 compatibility

The new ruby 3.1 use as default gem psych 4.0.3, with this version there is problem to load alias, i receive this error message
Unknown alias: defaults
To fix the problem you can change your yaml_to_hash method in this way:

    # Internal: Parses a yml file that can optionally use ERB templating.
    def yaml_to_hash(file_name)
      return {} if (content = File.open(file_name).read).empty?
      if Psych::VERSION > '4.0'
        YAML.load(ERB.new(content).result, aliases: true).to_hash
      else
        YAML.load(ERB.new(content).result).to_hash
      end
    end

In this way it works with ruby 3.1 and keep backwards compatibility

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.