Avoiding Constants in Rails

April 16, 2007 Chad Woolley

In his post “Redefining Constants” ( http://www.pivotalblabs.com/articles/2007/04/14/redefining-constants ), Brian Takita describes how to redefine Rails constants at test time. He points out that “it’s all dirty”, and that “…maybe the storage service can be an attribute that can be changed for individual tests.”.

In a comment, I suggested that a global configuration object would be a better approach, and here’s an example. It still uses a constant (as opposed to a global singleton object), but the constant is an object (a hash) which contain other values and objects. This avoids the need to redefine constants to use different values at test-time.

Create a sample Rails app

$ rails railsdi
$ cd railsdi/
$ ls
$ script/generate controller Sample
$ # create development/test databases

Declare the configuration hash

First, add a constant in boot.rb. Just ignore the warning to not modify boot.rb – it’s not talking about you. Put this at the beginning, right after the section that defines RAILS_ENV

boot.rb

REGISTRY = {}

Set per-environment defaults

Set any values or objects you want in the registry:

development.rb

REGISTRY[:key] = "development_value"

test.rb

REGISTRY[:key] = "test_value"

production.rb

REGISTRY[:key] = "production_value"

Verify that the correct values are used in each environment

Make a simple controller and view to verify the values are set per-environment:

sample_controller.rb

class SampleController < ApplicationController
  def index
    @registry_value = REGISTRY[:key]
  end
end

sample/index.rhtml

Rails Environment: <%= RAILS_ENV %>
Registry Value: <%= @registry_value %>

Start up the app in development and production environments, and hit http://localhost:3000/sample

Verify that registry values can be overridden at test time

sample_controller_test.rb

  def test__can_redefine_registry_value
    REGISTRY[:key] = 'overridden_value'
    get :index
    assert_equal 'overridden_value', assigns['registry_value']
  end

Summary

I think this is a pretty good approach, and it feels a lot like testing in an app that uses a Dependency Injection/Registry architecture (in other words, simple to override anything you want). I’d be interested to hear if there are any situations that could not use this approach, and would have to fall back to defining constants in the environment files.

It would also be interesting to hear if anyone has had success integrating a Rails application with a Dependency Injection approach (using Needle or a home-grown solution).

— Chad

About the Author

Biography

Previous
Taming JavaScript
Taming JavaScript

The explosion of client-side JavaScript in Web 2.0 applications has taken many developers by surprise. I'v...

Next
Redefining Constants
Redefining Constants

We all like a good oxymoron, like redefining constants. There are times where we need to redefine a constan...

×

Subscribe to our Newsletter

!
Thank you!
Error - something went wrong!