/s3_rails

A Rails resolver that retrieves templates from Amazon's S3 service

Primary LanguageRubyMIT LicenseMIT

S3-Rails — Store templates on AWS:S3

Gem Version Dependency Status Coverage Status

About

S3-Rails is a Rails resolver that retrieves templates from Amazon's S3 service. Imagine moving files from your app/views folder into an Amazon S3 bucket and serving them from there. The contents of the bucket are cached and can be refreshed.

This is particularly useful when you wish to change templates without re-releasing your application (e.g. Heroku slugs.)

So What Exactly Does This Do?

By default Rails searches the app/views folder for templates. You can, however, have it search multiple places, from almost any location. (For instance, in Crafting Rails Applications José Valim shows how to serve templates from a database.) S3-Rails adds an S3 bucket to this list of places.

For a given request, Rails uses the action name, extension, locale, variant, and available renderer list to generate a list of matching templates. In general the first one returned is rendered. The S3-Rails gem searches the configured bucket and returns matching templates for Rails to render. If a local template is not found first, Rails will render and serve the S3 template.

Future Possibilities

  • Pattern matching to exclude/include bucket files (right now all files in a bucket are loaded.)
  • A single central cache for multiple Rails instances (think Heroku.)
  • Multiple buckets per Rails app (matched to controller/action?)
  • (Submit an issue to put your idea here)

Installation

In your Gemfile:

gem 's3_rails'

Requirements

  • Rails 3.2

Usage

Set up Your Bucket

Create an S3 bucket, placing templates inside it as if it were the app/views directory. For instance, if you had an app/views/reports/yearly_report.pdf.prawn file, you would move it to reports/yearly_report.pdf.prawn inside the S3 bucket.

Now create an individual user under your Identity and Access Management AWS console, and give read only access to your bucket using policies.

Configure S3

Add a config/s3_rails.yml file to your Rails app with the following content (see below for policy examples):

s3_rails:
  access_key_id: YOUR_S3_ACCESS_KEY
  secret_access_key: YOUR_SECRET_ACCESS_TOKEN
  bucket: 'bucket-name'
  region: 'us-west-2'

When you created your bucket you will have specified the region. The access key and secret access key are specific to the user account used to access the bucket.

You can use ERB in this file to access environment variables:

  access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
  secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>

Controller

Then, in your controller, configure it to use the resolver:

append_view_path S3Rails::Resolver.instance
# or, to search S3 before the file system
prepend_view_path S3Rails::Resolver.instance

You can place that in ApplicationController to add it to all controllers at once.

Restart

Then restart your app if needed.

Reload cache

To reload the template cache upon the next request touch the tmp/s3_rails.txt file.

Or, somewhere inside your code (e.g. inside a controller action), call:

S3Rails::Resolver.instance.reload

Troubleshooting

Conflicts

If you use append_view_path and you have a local copy of the template it will be returned instead of the S3 template. This behavior is inherent to Rails. You must remove the local template for the S3 copy to be returned, unless you use prepend_view_path, which will make Rails call S3 before searching the local directory.

S3 Bucket and IAM Policies:

With this gem, you move the contents of the app/views directory to an S3 bucket. You should use Identity and Access Management to create a single user that has read only access to the bucket. That user's credentials should go into the s3_rails.yml file.

If you moved a view directory into a 'my_app' bucket, you would use the following two credentials:

To list the bucket contents:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:Get*",
        "s3:List*"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::my_app"
    }
  ]
}

To read the bucket contents:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:Get*",
        "s3:List*"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::my_app/*"
    }
  ]
}

Credit

David Burton asked me for this quite a while ago, and the idea simmered until I read Crafting Rails Applications by José Valim. Then I wrote most of this code while recording the "Rails Rendering" for Pluralsight. It seemed useful enough to make a gem of it. Many thanks to all of them!

Dependencies

Authors

Change log

  • October 1, 2014: 0.1.2 - ERB for config file
  • September 8, 2014: 0.1.1 - Resolver reload method
  • September 8, 2014: 0.1.0 - Initial release