14

It appears that now in Rails 4 using asset pipeline and the sprocket-rails gem, when images are processed, their filename is appended with an md5 fingerprint like css and javascript. While this makes sense because md5 fingerprints are awesome, it makes it increasingly difficult to access that image from javascript. In rails 3.2, I could access the image with /assets/image_name.jpg and it would serve properly, but in rails 4 that asset doesn't exist, it only exists with the md5 fingerprint in the name.

I know that rails provides helpers to access the image via erb <%= asset-url("image_name.jpg") %> but that is less ideal in javascript, because I am not using erb in my js. There are plenty of ways I could hack this with data-attributes serving in the views or using a script tag in my view and setting some globals, but I am looking for a nice solution to this problem, if it exists.

Any help is appreciated, thanks.

Bryan Ashley
  • 971
  • 7
  • 22

4 Answers4

1

Another option to consider (although I wouldn't recommend it) is to use a custom route in your application controller to grab the asset path for you in the controller and either return the url to the asset with the md5 hash or possibly just render the raw binary data of the asset (although this will add processing overhead to your application).

For example, you make a AJAX get request to http://yourapp.com/images?file=my_image.jpg

Then in your controller your action method would look like this:

def images
  ActionController::Base.helpers.asset_url(params[:file])
end

This would then return the url path to the asset. The downside to this method is that it requires that you make two requests on the JS side. The first to get the path to the asset and the second to actually load that asset with the returned path.

To reduce this down to one request you could have the application read the image from the file system and return the proper headers so the browser thinks it is an image being returned and therefor will render the url provided. However, this would be a lot more work for the application and a lot more unneeded disk IO on your server.

It may take two requests for each image on the client to achieve what you want but you have to sacrifice somewhere...

  • This could work with "one request on the JS side" by using `redirect_to` to simply redirect the browser request to the correct asset. While technically it still is two requests, you wouldn't need to write any more JS code to handle it. You'd do: `redirect_to ActionController::Base.helpers.asset_url(params[:file])` ...but bypassing the asset pipeline will have issues (caching, etc.) so it is definitely not recommended for actual production use. One-offs and simple let-me-see-this-thing kind of tests in prod should be fine though. – Karl Wilbur Sep 11 '15 at 15:22
  • Yea @KarlWilbur is right, redirect_to seems like a much cleaner solution. – John Saltarelli Sep 12 '15 at 17:09
0

Why do you need to use the asset pipeline for images? I get the hashing behavior. But normally the assets would be preprocessed. If you put the images in the public hierarchy as in olden times, you would get normal path routing.

Here's a quote from the Asset Pipleline guide that I think might be germane. "Assets can still be placed in the public hierarchy. Any assets under public will be served as static files by the application or web server. You should use app/assets for files that must undergo some pre-processing before they are served."

Virmundi
  • 2,497
  • 3
  • 25
  • 34
  • What if I want to leverage the fingerprinting of image assets to break cache on updates? How can I access a fingerprinted image from a javascript variable? – Micah Mar 15 '14 at 15:49
  • I'm looking for the same thing, and I found this. It does what you're looking for. https://github.com/johnnypez/assets_js. – Steven Kampen Apr 17 '14 at 20:51
0

Unfortunately, I think that you are stuck either adding an ERB extension to your JS and using the asset helpers, or else not using the asset pipeline for the assets.

chad_
  • 3,749
  • 2
  • 22
  • 22
-1

When you say "I am not using erb in my js", do you mean you don't want to, or simply that you aren't? Because you can!

If you rename the relevant JS files with the extension .js.erb then you can use the asset_url helper in these files like so:

var src = "<%= asset_url('photo.jpg') %>";
Jez
  • 74
  • 1
  • 3
  • Not really a good option if you're dealing with a lot of images and populating the src dynamically (in JS)--instead of hard coding it like you are. – Mark Fraser May 01 '16 at 03:44