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:
<style>
.main_app {
font-size: 20px;
color: #fff;
background: url(<%= randomized_background_image %>) no-repeat center center fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
}
</style>
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:
ActionController::Base.helpers.image_path("/assets/bg0.jpg")
Or
ActionController::Base.helpers.image_path("bg0.jpg")
And all manner of other trickery to get it working. Alas - it was not to be.
The final solution I settled on? Hardcode the damn links to the CDN files.
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