Troubleshooting the Rails Asset Pipeline for Cloud Application Platforms

I recently deployed a Rails application to a cloud application platform in order to gather some feedback. The application ran just fine on my development machine and I couldn’t wait to push it to a server so other people can test it. I had this preconceived notion that my app would magically appear on the public internet with the push of a button (you would think I knew better by now). The process took a few sleepless nights to complete. This blog post will explain the issues I encountered with the deployment and how I resolved them.

My first thought was to deploy my app to Heroku since deploying an app to Heroku was one of the first things I had learned when reading through the popular Rails Tutorial. Once I had pushed my app to Heroku I immediately noticed that something went terribly wrong. My app was not loading CSS! The app’s logo loaded just fine but there was absolutely no formatting. Just white background with black text in a single column. Thinking that there must have been an incompatibility issue with my app and Heroku I decided to try deploying to a Digital Ocean server using the Cloud66 platform. Same result. I then knew something was wrong with my configuration.

After doing some basic research I discovered that many other people run into this issue as well. I saw many different solutions that, at the time, I knew very little about. Before doing any research at all I highly recommend reading the Ruby on Rails documentation on the asset pipeline. Had I read that sooner I think I would have came to a solution in a shorter amount of time and with less stress.

The issue is with the /config/environments/production.rb and /config/application.rb configuration files. I will post my copies of these files further below. For now I want to explain the important configurations settings.

The first thing to check is that the asset pipeline is enabled. Make sure config.assets.enabled is set to true in your application.rb file:

 config.assets.enabled = true

In that same file you also want to ensure that the following is set to false:

config.assets.initialize_on_precompile = false

This setting is required in order to get your rails app properly deployed to Heroku or Cloud66+Digital Ocean. I use the word properly because setting this to true will enable assets to be compiled live as the app is running. This uses much more memory and leads to poor performance. Make sure you set this to false to have assets precompiled before running (this is explained later in this post).

You will most likely want to compress your Javascript files and have the default Ruby gem uglifier handle the compression for you (you can read more about this in the Ruby on Rails documentation). In your production.rb file make sure the following setting is set to true:

config.assets.compress = true

You will then want to ensure that all of your CSS and Javascript files will be included. In your production.rb file make sure config.assets.precompile is set to the following:

 config.assets.precompile = [ /\A[^\/\\]+\.(ccs|js)$/i ]

The above two settings were the causes of my issues. After fixing the settings above I noticed Javascript errors in my console when I tried to precompile my assets. This eventually led me to discovering a missing “}” in one of my CSS files. Make sure that these two asset precompile settings are set properly so that you can solve any potential syntax issues locally in development mode.

Now that those configurations have been set you are ready to precompile your assets in your local development environment. To precompile your assets, type the following in your console:

bundle exec rake assets:precompile

Once this operation completes you may see errors like I did. Carefully read through the errors to pick out the error message, the file that caused the error, and the line number where it may be occurring.

After your assets are precompiled you will need to commit your changes and push them to your git respository:

git add .

git commit -a -m “precompiled assets”

git push

Lastly you will need to push the newly precompiled assets to your Production deployment. For Heroku, simply push your code to your server with the following:

git push Heroku master

For Cloud66, click on the Deploy icon on your dashboard to deploy with your new code changes.

Here are my production.rb and application.rb files for your reference:

production.rb

AppName:Application.configure do
# Settings specified here will take precedence over those in config/application.rb

# Code is not reloaded between requests
config.cache_classes = true

# Full error reports are disabled and caching is turned on
config.consider_all_requests_local = false
config.action_controller.perform_caching = true

# Disable Rails’s static asset server (Apache or nginx will already do this)
config.serve_static_assets = false

# Compress JavaScripts and CSS
config.assets.compress = true

# Don’t fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = true

# Generate digests for assets URLs
config.assets.digest = true

# Defaults to nil and saved in location specified by config.assets.prefix
# config.assets.manifest = YOUR_PATH

# Specifies the header that your server uses for sending files
# config.action_dispatch.x_sendfile_header = “X-Sendfile” # for apache
# config.action_dispatch.x_sendfile_header = ‘X-Accel-Redirect’ # for nginx

# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true

# See everything in the log (default is :info)
# config.log_level = :debug

# Prepend all log lines with the following tags
# config.log_tags = [ :subdomain, :uuid ]

# Use a different logger for distributed setups
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)

# Use a different cache store in production
# config.cache_store = :mem_cache_store

# Enable serving of images, stylesheets, and JavaScripts from an asset server
# config.action_controller.asset_host = “http://assets.example.com”

# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
config.assets.precompile = [ /\A[^\/\\]+\.(ccs|js)$/i ]

# Disable delivery errors, bad email addresses will be ignored
# config.action_mailer.raise_delivery_errors = false

# Enable threaded mode
# config.threadsafe!

# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation can not be found)
config.i18n.fallbacks = true

# Send deprecation notices to registered listeners
config.active_support.deprecation = :notify

# Log the query plan for queries taking more than this (works
# with SQLite, MySQL, and PostgreSQL)
# config.active_record.auto_explain_threshold_in_seconds = 0.5

#TODO: Edit mailer config
config.action_mailer.default_url_options = { :host => ‘localhost:3000’ }

# config/environments/production.rb
config.paperclip_defaults = {
:storage => :s3,
:s3_credentials => {
:bucket => ENV[‘AWS_BUCKET’],
:access_key_id => ENV[‘AWS_ACCESS_KEY_ID’],
:secret_access_key => ENV[‘AWS_SECRET_ACCESS_KEY’]
}
}
end

application.rb

require File.expand_path(‘../boot’, __FILE__)

# Pick the frameworks you want:
require “active_record/railtie”
require “action_controller/railtie”
require “action_mailer/railtie”
require “active_resource/railtie”
require “sprockets/railtie”
# require “rails/test_unit/railtie”

if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
Bundler.require(*Rails.groups(:assets => %w(development test)))
# If you want your assets lazily compiled in production, use this line
#Bundler.require(:default, :assets, Rails.env)
end

module AppName
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# — all .rb files in that directory are automatically loaded.

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)

# Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named.
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]

# Activate observers that should always be running.
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer

# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run “rake -D time” for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = ‘Central Time (US & Canada)’

# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join(‘my’, ‘locales’, ‘*.{rb,yml}’).to_s]
# config.i18n.default_locale = :de

# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = “utf-8”

# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]

# Enable escaping HTML in JSON.
config.active_support.escape_html_entities_in_json = true

# Use SQL instead of Active Record’s schema dumper when creating the database.
# This is necessary if your schema can’t be completely dumped by the schema dumper,
# like if you have constraints or database-specific column types
# config.active_record.schema_format = :sql

# Enforce whitelist mode for mass assignment.
# This will create an empty whitelist of attributes available for mass-assignment for all models
# in your app. As such, your models will need to explicitly whitelist or blacklist accessible
# parameters by using an attr_accessible or attr_protected declaration.
config.active_record.whitelist_attributes = true

# Enable the asset pipeline
config.assets.enabled = true

# Version of your assets, change this if you want to expire all your assets
config.assets.version = ‘1.0’

#Required for Heroku or Cloud 66+DO deployment
config.assets.initialize_on_precompile = false

#config.serve_static_assets = false

#Prevent passwords from being written to logs
config.filter_parameters += [:password, :password_confirmation]
end
end

Please feel free to contact me with any questions about this process.

One Reply to “Troubleshooting the Rails Asset Pipeline for Cloud Application Platforms”

  1. Woah! I’m really enjoying the template/theme of this site. It’s simple, yet effective.
    A lot of times it’s hard to get that “perfect balance” between usability and
    visual appeal. I must say you have done a excellent job with this.
    Also, the blog loads extremely fast for me on Internet explorer.
    Outstanding Blog!

Leave a Reply

Your email address will not be published. Required fields are marked *