views:

480

answers:

2

I have some settings I need in a Javascript file -- servers to connect to -- that changes based on my environment. For development, test, and staging, I want to use the staging servers; for production, the production servers. I already have the settings in Ruby (configured in my environment/xyz.rb files). So far, I've been dynamically creating the JS files at request time with an application.js.erb file and a custom route. This is pretty slow, though, and it means creating an extra controller and views directory just for this file.

I would prefer to have a template file and a rake task that generates the correct version from the template and places a static file in the public/javascripts directory. Has anyone tried something like this? What did you use for rendering? Where did you put the template file and the rendering code?

Or is it better to just keep the dynamic version and cache it in production?

+2  A: 

Can you do something like this?

<% javascript_include_file "#{RAILS_ENV}.js" %>

I do something similar, though it is not with a JS file, but with some RB files ... and I do it for the same reason, determining which servers to connect to.

For me, I have an rb file in my "lib" directory called "constants.rb". This file has a few if statements that switch based on environment (development, test, staging, or production) that switch out the values of the ip addresses that I need to attach to. It is peppy enough for my purposes on the behemoth of a machine that I have the application running on.

Here is a sample:

if ENV['RAILS_ENV'] != "production" ## if the rails environment is development or staging then use the test server
  @@IP_ADDRESS = "10.16.121.173" ## the test server
else ## if the Rails environment is production, then use the live server.
  @@IP_ADDRESS = "10.16.8.44" ## The is the shared IP address
end
salt.racer
It's a great idea. There aren't likely to be hundreds, or even dozens of environments, so there won't be tons of files. I might suggest a slightly more informative name, like "settings_#{RAILS_ENV.downcase}.js" or "constants_..."
James A. Rosen
The more informative the name of the file the better. Glad you like the idea.
salt.racer
A: 

Using rake task to generate these javascript files is really an option. I'm using rake tasks to generate i18n translation files for JS frontend from translation files in YAML format. One option is to use ERB for templates. I'd put rakefile under lib/tasks/foo.rake and templates under lib/tasks/foo/foo.erb. If your JS template is not very complex, i'd suggest using plain Hash.to_json method to generate javascript contents:

namespace :js do
  task :generate_config => :environment do
    File.open("#{RAILS_ROOT}/public/javascripts/configuration.js", 'w') do |out|
      config = {:option_1 => 'Value 1', :option_2 => 'Value 2'}
      out << "var CONFIG = #{config.to_json}"
    end
  end
end

But configuration files are something you just don't want to forget to be regenerated when your configuration source data has been changed. I'm using a solution to generate "minified" JS files on production environment to append huge number of javascript files together so i can save on HTTP requests. But you can use basically the same solution. It works great if you use Capistrano to deploy your application.

In file app/helpers/application_helper.rb create new helper method which is available globally:

module ApplicationHelper
  def javascript_include_config_tag
    if ActionController::Base.perform_caching
      unless File.exists?("#{RAILS_ROOT}/public/javascripts/configuration.js")

        #
        # TODO: Generate configuration data in here
        #
        config = 'configuration file contents'

        File.open("#{RAILS_ROOT}/public/javascripts/configuration.js", 'w') do |out|
          out << config
        end
      end
      javascript_include_tag('configuration')
    else
      # Link to js generated dynamically on each request. Useful in development.
      javascript_include_tag('PATH_TO_DYNAMICALLY_GENERATED_JS')
    end
  end
end

And in your view you just include javascript with

<%= javascript_include_config_tag %>

The idea here is that this JS configuration file is being generated only first time on page load after fresh Capistrano deploy. It also has a huge downside that you cannot request configuration.js file before first page generate, but in my app, it works fine so far.

Priit