Post

Sometimes the asset pipeline isn't flexible enough

In my latest application, I wanted to display full-width and full-height background images randomly from some web source.

I couldn't find any documentation about how to call a background image from a URL - and it's true that these things change over time and one day my application my hit a 404.  So I ended up putting 9 images that I liked (and own the rights to) in my assets/images folder, precompiling and pushing the application live.

The code for the randomization is like this:

I put this in my layout file - application.html.erb.  Normally you wouldn't include CSS definitions like this directly in the html file - you put them in a css/scss/sass file.

But here we have a learning opportunity - we want to call a helper method that we defined called 'randomized_background_image' and we need to call it using ERB syntax so that it will be interpreted.

I couldn't think of a better way to do it directly in the CSS file (and I found most of what I needed on Stack Overflow, so I left it alone).  I have a definition inside my primary CSS file in case this override ever chokes, but this helper method goes to Application Helper and is defined like so:

module ApplicationHelper def randomized_background_image images = [ ("/assets/bg0.jpg"), ("/assets/bg1.jpg"), ("/assets/bg2.jpg"), ("/assets/bg3.jpg"), ("/assets/bg4.jpg"), ("/assets/bg5.jpg"), ("/assets/bg6.jpg"), ("/assets/bg7.jpg"), ("/assets/bg8.jpg") ] images[rand(images.size)] end end

Pushing this out - you have a nice random image effect for the background of your site or app.

Now there is a problem - which is the namesake of this post - there is no way that I could find to make those assets actually come from my defined asset site.

I use Amazon CloudFront in most of my projects, and I end up with a convention of:

http://cdn0.hostname.com

http://cdn1.hostname.com

http://cdn2.hostname.com

And so on through 9.  This allows us to skirt the limitation of a browser only opening a max of two simultaneous connections to a host.  When we want to serve lots of css, js, and image files concurrently (and quickly), we make sure to fake a bunch of random hostnames (which all go back to the same CloudFront URL of course) in order to get those things moving across the inter-tubes.

So back to our problem - normally from a view you can call:

<%= image_tag "bg" %>

and rails will automagically figure things out for you - grab the image from either your public/assets directory or from your /assets directory if you have the fallback option enabled (disable it in production please).

In your CSS files, you might have used something like:

background-image: url('image.jpg');

In order to serve these assets through the asset pipeline.

But what if you are in my shoes?  You want to serve the assets through the asset pipeline from a Class?

The asset helper tags weren't really meant for that.

I tried solutions like the following:

``` default ActionController::Base.helpers.image_path("/assets/bg0.jpg")

CODE0 default ActionController::Base.helpers.image_path("bg0.jpg")

CODE1 default module ApplicationHelper def randomized_background_image images = [ ("http://cdn0.hostname.com/assets/bg0.jpg"), ("http://cdn1.hostname.com/assets/bg1.jpg"), ("http://cdn2.hostname.com/assets/bg2.jpg"), ("http://cdn3.hostname.com/assets/bg3.jpg"), ("http://cdn4.hostname.com/assets/bg4.jpg"), ("http://cdn5.hostname.com/assets/bg5.jpg"), ("http://cdn6.hostname.com/assets/bg6.jpg"), ("http://cdn7.hostname.com/assets/bg7.jpg"), ("http://cdn8.hostname.com/assets/bg8.jpg") ] images[rand(images.size)] end end ```