CloudCrooner

Manage your Sinatra app's assets with Sprockets and sync them with Amazon S3.

Cloud Crooner will run a Sprockets instance and configure helpers for your views. Create a rake task to compile your assets and upload them to the cloud, and use helper methods to make sure you're always pointing to the right asset paths for your environment. In prod, your assets will have appended to their names an MD5 hash of their contents which updates when your assets change, ensuring that your users will always be served the freshest assets without needing to worry about expiring caches.

Installation

Add this line to your application's Gemfile:

gem 'cloud_crooner'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install cloud_crooner

Configuration

Cloud Crooner has many configuration options which can be set in a configure block. Explicit configuration is optional.

CloudCrooner.configure do |config|
  config.prefix = '/assets'
end

serve_assets - where and how to serve assets. You have three options:

  • local_dynamic - default in test & dev environments. Serves assets locally with Sprockets, dynamically generating them.
  • local_static - serves compiled assets from public_folder. Be aware that attempting to test this on your machine using rackup or thin will not work. Rack does not serve files from \public. If you want to see static assets in action without messing with Rack internals, you must run shotgun or something like it.
  • remote - default in prod - serves compiled assets from S3

public_folder - the public folder of your application. By default set to /public. If you are using a different public folder, you must set it in this config block as well as in your application.

prefix - the path from root where you keep your assets. By default it is /assets. Your compiled assets will be placed in public_folder/prefix. It will also be the pseudo-folder on S3 where your assets will be stored, so the paths will look something like http://bucket-name.s3.amazonaws.com/prefix/filename.

sprockets - by default, this will be your Sprockets environment and it will add to its load path the paths set in the config option asset_paths.

asset_paths - the load paths for your Sprockets instance. By default it will add the prefix directory.

manifest - the Sprockets manifest. By default, it will be created in public_folder/prefix. The manifest's location is also the folder where assets will be compiled to.

assets_to_compile - an array of the assets you would like compiled, given by their logical Sprockets paths. If Sprockets knows how to gzip your assets (it can do css and js by default), it will also gzip them.

backups_to_keep - the number of compiled asset backups to keep. Default is 2. When running the sync task, if an asset's content has changed, it will be recompiled. If there are already more than the set number of backups present, the oldest asset will be deleted locally, removed from the manifest, and deleted remotely.

Amazon S3 settings and credentials

See "Hooking Up With Your Amazon S3 Account" for details.

bucket_name - the name of your AWS S3 bucket.

region - the region of your AWS S3 bucket.

aws_access_id_key - aws credentials.

aws_secret_access_key - aws credentials.

No Configuration

If you're keen to run everything on defaults, you will still need to run one command in order to get the helpers working:

CloudCrooner.configure_sprockets_helpers

Normally this is called at the end of the CloudCrooner.configure method. This method also assumes you have put the S3 settings into ENV outside of the app.

Hooking Up With Your Amazon S3 Account

After you have created an S3 account, you will will be provided with an "access key id" and a "secret access key". You will also need your bucket name and the bucket's region. One of the ways to find the region is by going to the S3 console and checking the end of the URL: it will look something like us-west-1. Cloud Crooner will look for your AWS credentials in your ENV by default. Do not put your credentials anywhere they can be checked into source control. I would suggest loading them into the env with your bash login scripts. The env keys that will be checked by default are:

ENV["AWS_SECRET_ACCESS_KEY"]  # the secret access key given by Amazon
ENV["AWS_ACCESS_KEY_ID"]      # access key id given by Amazon 
ENV["AWS_BUCKET_NAME"]        # the name of your bucket 
ENV["AWS_REGION"]             # the region of your bucket

You may also set these in the Cloud Crooner config block, but please do not directly set the two Amazon credentials here.

CloudCrooner.configure do |config|
  config.aws_secret_access_key = ENV["MY_AWS_SECRET"] 
  config.aws_access_key_id = ENV["MY_ACCESS_KEY"]
  config.bucket_name = "super-cool-bucket"
  config.aws_region = "eu-west-1"
end

Setting Up Your App:

I have thrown together a very simple application as an example.

In a file of your choosing (in this case /config/cloud_crooner_config.rb) run the configuration block with your desired settings.

require 'cloud_crooner'

CloudCrooner.configure do |config|
  config.backups_to_keep = 1
  config.asset_paths = %w( assets/stylesheets ) # assuming this is where I put my sass files
  config.assets_to_compile %w( main.css )  # assuming this is the file I want to compile
end

In config.ru, require this file, and set up the following:

require './config/cloud_crooner_config.rb' # your Cloud Crooner config file
require './app.rb' # your app file

map '/' + CloudCrooner.prefix do
  run CloudCrooner.sprockets
end

map '/' do
  run App # your application class name
end

You have to register the helpers in your application so they can find your assets:

class App < Sinatra::Base
  helpers do
    include Sprockets::Helpers
  end
end

The helpers which you can use are detailed below.

To compile and upload the assets, in your rakefile:

require './config/cloud_crooner_config.rb'

namespace :assets do
  desc 'compile and sync assets' do
  task :sync do
    CloudCrooner.sync
  end
end

Now on the command line, run rake assets:sync and the following will happen:

  1. new or changed assets will be compiled into public/assets
  2. assets will be uploaded to the S3 bucket, which is set in ENV elsewhere. If an asset has a gzipped file associated with it and the gzip is smaller than the original file, the gzip will be uploaded in its place
  3. manifest will be updated
  4. old backups locally and remotely will be deleted

Running your app in development mode will serve uncompiled assets locally (from /assets), and running your app in production mode will serve your compiled assets from S3. If you have serve_assets set to local_static your compiled assets will be served from public/assets.

If you want to precompile and upload your assets every time you spin up your app, you can put the configure block directly into config.ru and after config run CloudCrooner.sync.

Helpers

Helper methods are provided for use in your views using the sprockets-helpers gem.

stylesheet_tag - put this in your views to insert an html tag referencing a stylesheet in the Sprockets load path. For example, if you have /assets/stylesheets/application.scss and have placed assets/stylesheets in the load path, you would write:

<%= stylesheet_tag 'application' %>

and in dev it will compile to

<link rel="stylesheet" href="/assets/application.css">

in prod it will compile to

<link rel="stylesheet" href="http://my-bucket.s3.amazonaws.com/assets/application.css">

javascript_tag - similar to stylesheet_tag

asset_tag - similar to stylesheet, but you pass a block to generate a tag of your choosing.

asset_tag('main.js') { |path| "<script src=#{path}></script>" }

will generate

<script src=/main.js></script>

asset_path - returns the path to an asset, no tag.

Notes About Sass and Sprockets

If you are using sass files, you should use the sprockets-sass and sass gems to help Sprockets cope (sprockets-sass still necessary as of 06/30/13 for functional Sinatra @imports, email me if this changes).

Specifically for Sass files, do not use the Sprockets directives - use @include. See here for more details:

Structure Your Sass Files with @import

You can also set any sass (or other supported processor) specific options in your config.ru: Sprockets::Sass.options[:style] = :compressed See Sprockets for details.

Contributing

If there's a feature you'd like to see, when you create an issue, please supply a valid use case. If you'd like to fix a bug or add a feature yourself, please update relevant tests before submitting a pull request.