Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I run SOME initializers when doing a Rails assets:precompile?

Background

I have an app that I recently updated to Rails 3.2.1 (from Rails 3.0.x) and have refactored the JS and CSS assets to make use of the new asset pipeline. The app is hosted on Heroku with the Celadon Cedar stack.

App Config

I keep application specific configuration in a YAML file called app_config.yml and load it into a global APP_CONFIG variable using an initializer:

# config/initializers/load_app_config.rb

app_config_contents = YAML.load_file("#{Rails.root.to_s}/config/app_config.yml")
app_config_contents["default"] ||= {}
APP_CONFIG = app_config_contents["default"].merge(
                       app_config_contents[Rails.env] || {} ).symbolize_keys

Asset Compilation on Heroku

Heroku has support for the Rails asset pipeline built into the Cedar stack. When you push an app to Heroku it automatically calls rake assets:precompile on the server as a step in the deploy process. However it does this in a sandboxed environment without database access or normal ENV vars.

If the application is allowed to initialize normally during asset precompilation an error is thrown trying to connect to the database. This is easily solved by adding the following to the application.rb file:

    # Do not load entire app when precompiling assets
    config.assets.initialize_on_precompile = false


My Problem

When initialize_on_precompile = false is set, none of the initializers in config/initializers/* are run. The problem I am running into is that I need the APP_CONFIG variable to be available during asset precompilation.

How can I get load_app_config.rb to be loaded during asset compilation without initializing the entire app? Can I do something with the group parameter passed to Rails::Application.initialize! ?

like image 794
jshkol Avatar asked Feb 10 '12 21:02

jshkol


People also ask

How do you Precompile in Rails?

To compile your assets locally, run the assets:precompile task locally on your app. Make sure to use the production environment so that the production version of your assets are generated. A public/assets directory will be created. Inside this directory you'll find a manifest.

What does bundle exec rake assets Precompile do?

4.1 Precompiling Assets. Rails comes bundled with a rake task to compile the asset manifests and other files in the pipeline to the disk. Compiled assets are written to the location specified in config.

What does rake assets Clean do?

The clean it removes the old versions of the precompiled assets while leaving the new assets in place. Show activity on this post. rake assets:clean removes compiled assets. It is run by cap deploy:assets:clean to remove compiled assets, generally from a remote server.


2 Answers

Rails lets you register initializers only in certain groups, but you need to use the Railtie API:

# in config/application.rb

module AssetsInitializers
  class Railtie < Rails::Railtie
    initializer "assets_initializers.initialize_rails",
                :group => :assets do |app|
      require "#{Rails.root}/config/initializers/load_config.rb"
    end
  end
end

You don't need to check if AppConfig is defined since this will only run in the assets group.

And you can (and should) continue to use initialize_on_precompile = false. The load_config.rb initializer will be run when initializing the app (since it's in config/initializers) and when pre-compiling without initializing (because of the above code).

like image 150
Gabe Kopley Avatar answered Jan 01 '23 07:01

Gabe Kopley


Definitely check out asset_sync on github. Or our Heroku dev centre article on Using a CDN asset Host with Rails 3.1 on Heroku.

The issues with environment variables have recently been solved by a Heroku labs plugin, that makes your application's heroku config variables accessible during compilation time. To enable this, read about the user_env_compile plugin.

Also. There is quite a big performance improvement in using asset_sync vs letting your application lazily compile assets in production or serving them precompiled directly off your app servers. However I would say that. I wrote it.

  • With asset_sync and S3 you can precompile assets meaning all the assets are there ready to be served on the asset host / CDN immediately
  • You can only require the :assets bundle in application.rb on precompile, saving memory in production
  • Your app servers are NEVER hit for asset requests. You can spend expensive compute time on, you know. Computing.
  • Best practice HTTP cache headers are all set by default
  • You can enable automatic gzip compression with one extra config
like image 44
David Rice Avatar answered Jan 01 '23 07:01

David Rice