DEV Community

Cover image for Auto-reload `config_for` files in Rails
Mario
Mario

Posted on

4 2

Auto-reload `config_for` files in Rails

In Rails projects I often use YAML files to organize app-wide values or configurations.

# config/settings.yml
shared:
  important_value: 42

development:
  default_from_email: 'development@example.com'

test:
  default_from_email: 'test@example.com'

production:
  default_from_email: 'production@example.com'
Enter fullscreen mode Exit fullscreen mode

In the application configuration we create a new configuration:

# config/application.rb
module RailsApp
  class Application < Rails::Application
    # ...
    config.settings = config_for(:settings)
  end
end
Enter fullscreen mode Exit fullscreen mode

We can access these values using Rails.configuration.settings, for example:

# $ RAILS_ENV=test bin/rails c
# Loading test environment (Rails 7.0.0)
Rails.configuration.settings[:important_value]    # => 42
Rails.configuration.settings[:default_from_email] # => "test@example.com"
Enter fullscreen mode Exit fullscreen mode

Unfortunately the configuration is not reloaded automatically. If we change the important_value and refresh the page, we'd still see the old value. In order to see the value, we'd need to restart the server first. This can be confusing and tedious, particularly in development.

Here's a way to reload the configuration every time the file changes.

Create a new file config/initializers/config_for_reloader.rb:

# config/initializers/config_for_reloader.rb
if Rails.env.development?
  config_for_reloader = ActiveSupport::FileUpdateChecker.new(["config/settings.yml"]) do
    Rails.application.config.settings = Rails.application.config_for(:settings)
  end

  ActiveSupport::Reloader.to_prepare do
    config_for_reloader.execute_if_updated
  end
end
Enter fullscreen mode Exit fullscreen mode

In our case the block contains the same instruction as in config/application.rb for loading the YAML file.

At this point, I would have expected that Rails picks up the changes automatically after the file config/settings.yml is modififed, but for some reason it does not. It only reloads the file and sets the configuration after an "application file" (a model, template, controller, routes, etc.) is modified.

We can workaround this by adding config/settings.yml to the eager_load_paths:

# config/application.rb
module RailsApp
  class Application < Rails::Application
    # ...
    config.settings = config_for(:settings)
    config.eager_load_paths << Rails.root.join("config/settings.yml")
  end
end
Enter fullscreen mode Exit fullscreen mode

(If anybody knows why that is necessary, I'd be interested.)

Now, the configuration file is reloaded after changing it and a page refresh would show the latest value.

(Cover image by Christopher Alvarenga on Unsplash)

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

Top comments (4)

Collapse
 
colindean profile image
Colin Dean

The shared key wasn't working for me on a Rails 5 app. I needed to use YAML anchors as mentioned in this SO answer.

shared: &shared
  foo: bar

development:
  <<: *shared
testing:
  <<: *shared
production:
  <<: *shared
Enter fullscreen mode Exit fullscreen mode
Collapse
 
lxxxvi profile image
Mario

Thank you @colindean , that's useful information!

The shared key was introduced in PR #37913 which was in the early stages of Rails 6.

Collapse
 
braindeaf profile image
RobL

I'm just wondering how awful this is if I use this solution production.

I have a case where I need to update a config that is called in middleware. e.g. creating a hostname redirect for a multi-tenant application based on a YAML config. It would be wasteful to restart the whole application, but inefficient to read a file in on every request.

Collapse
 
lxxxvi profile image
Mario

Good question. This article is particurlarly meant for development, I'd be hesitant to use this approach in production.

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay