How can duplication be removed from this?

class Authentication
  PROVIDERS = if Rails.env.production?
                %w(weibo open_wechat wechat)
                %w(weibo open_wechat wechat developer)

Rails already has environment-specific configuration via the files in config/environments. As explained in the Rails Guides, you can simply do

# in config/application.rb (the default config)
config.authentication_providers = %w(weibo open_wechat wechat)


# in config/environments/development.rb (overrides the default)
config.authentication_providers = %w(weibo open_wechat wechat developer)

Edit: Or, as 200_success points out in the comments, you can simply add "developer" to the existing list:

# add another item to the default config instead of redefining it completely
config.authentication_providers += %w(developer)


config.authentication_providers << "developer"

Note that the strictest configuration is used as the default - the less strict one you have to explicitly set for a given environment (such as development or test).

You code then becomes:

class Authentication
  PROVIDERS = Rails.configuration.authentication_providers

Or you can simply skip the constant, since there's no need for it anymore; the list isn't being defined in class at all.

But another, and often times better, way to handle stuff like this is to use environment (ENV) variables, as explained in chapter 3 of "The 12 Factor App" (read it). You'll set the variables one way for production, another way for development, yet another for test perhaps, and so on if you have more environments.

Another great explanation, although it's now subscription-only*, is this Railscast episode. While the episode isn't brand-new anymore, the advice in it is absolutely still valid.

Anyway, one major point is that ENV configuration do not need to be included in source control, which is great if the configuration contains sensitive things like API keys or passwords. Rails already hits upon this point for the secret_key_base variable, where, in config/secrets.yml, it says simply:

# Do not keep production secrets in the repository,
# instead read values from the environment.
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>

There are many ways to set ENV vars; personally, I often use this gem, but there are many others. And of course the ENV handling built into you OS.

Again, there are many way to handle it. The basic premise is that stuff that changes from environment to environment should be accessed through the ENV. That's what it's for, after all. Again, read this.

*) Well worth the $9! Since Railscasts on indefinite - possibly permanent at this point - hiatus, you'll only be charged $9 for the first month, but there won't be a monthly charge (unless Ryan decides to start back up again). See this announcement for details.

  • \$\begingroup\$ Just what I was going to write. You can even write config.authentication_providers += %w(developer) in development.rb — I just tested it. \$\endgroup\$ – 200_success Jan 21 '15 at 6:21
  • \$\begingroup\$ @200_success Ah, yes, good point! I'll mention that \$\endgroup\$ – Flambino Jan 21 '15 at 10:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.