Serving only image assets from CloudFront with Rails - ruby-on-rails

I recently switched to using CloudFront as a CDN to serve my assets using the simple
config.action_controller.asset_host = "url of your cloudfront distribution" in my config file.
All works well, CF pulls in assets that it doesn't have just fine, serves them just fine, is faster than using the asset pipeline.
However, for a variety of reasons, some of our JS breaks when served from CF and not our own server. So I am looking for a way to use CF just for image (or image/css) assets, and still serve the compiled application.js file directly from our own server.
Any ideas?

Rails allows you to set config.action_controller.asset_host to be a proc. That way you can have as much control as you like over the selection of the asset host. For example:
config.action_controller.asset_host = Proc.new { |source|
if source.ends_with?('.jpg')
"http://cdn.example.com"
else
nil
end
}
See the api docs for more details.

Related

Problems serving .js and .css assets cloudfront CDN Heroku Rails 4 App

I am trying to host the assets of my Rails 4 App over Cloudfront CDN. I used to use asset_sync and s3 but I wanted to switch over to a CDN.
When I go to my Heroku App, I see that all the pages are just bare HTML. None of the JS or CSS is being loaded.
These are the errors I am getting from my Console:
Screenshot of console errors: http://i61.tinypic.com/15rxdsj.jpg
Also, I am not sure if I have set up my Origin Domain Name and Origin Path correctly on the Cloudfront Origin Settings.
Currently I am using my heroku app url as the Origin Domain Name and "/production/assets" as the Origin Path.
Production.rb file: http://pastebin.com/2dzLpGfE
I have been trying unsuccessfully for the past week to get the Heroku app to display the CSS and JS. I would greatly appreciate any insight. Thanks in advance!
Moving to Cloudfront isn't as drastic as change as you seem to think if you had everything working from S3. After all, Cloudfront simply distributes the contents of your S3 bucket to edge locations. This means you just have to let Rails know to look for the CDN and not S3.
There are a lot of things that could be going on. You could have misconfigured Cloudfront, which should be pointing to your S3 bucket as the origin. You should test that setup by checking to see an asset in the browser by using the Cloudfront URL. The main point is that Cloudfront should have no idea about your Rails app.
Meanwhile, you can still use AssetSync to push your assets to S3 "underneath" an assets path. You must also configure config.action_controller.asset_host as described here.

Serving images in rails

For every version of my app, I upload my assets to the cloud CDN, and the images on the website are loaded as something like imagename-somehash.
I have static images that are large, i.e like carousel images, which don't change often or at all. So even when the app changes, they can remain cached by clients who previously visited the website.
How would one do that? Any images I have under app/assets folder gets upload to CDN with the imagename-somehash format, so the image changes with every version of the app.
I'm using rails 4.2. Is this possible?
In rails guides there is an article What is Fingerprinting and Why Should I Care? which gives some insights about that hash on the end of a file and how it works.
Check your environments files. In production you may want config.assets.digest to be true.
You can put these images in public folder and can mention full url in views for these images
OR You can also put it on
vendor/assets/images
but in that case you would have to disabled precompile path
If you want to serve only some assets from your CDN, you can use custom :host option your asset helper, which overwrites value set in config.action_controller.asset_host.
<%= asset_path 'image.png', host: 'mycdnsubdomain.fictional-cdn.com' %>

Rails Engine asset images are not compiled

I have a strange behavior with my engine gem https://github.com/antpaw/bhf on the production environment. The bhf/application.js and bhf/application.css is compiled the way you would expect it and also linked the right way in the template. But none of the assets/bhf/image files are compiled and can be found in shared/assets/bhf/ on production server, unless i change
config.serve_static_assets = false
to true in production.rb?
How bad is it to use this setting? And is there a way for my engine to work out-of-the-box?
Per your gemspec https://github.com/antpaw/bhf/blob/master/bhf.gemspec
It has a dependency on rails v4 s.add_dependency(%q<rails>, [">= 4.0.0"])
I suspect its related to asset digest. Where the assets are getting compiled as expected with digest but are referred from respective CSS without digest.
Its a possible issue with sprockets-rails discussed here issue#49
non-stupid-digest-assets - not so good but preferred solution
It will copy non-digested assets to /public
Are you using Webrick in production? If so, you will need to set config.serve_static_assets = true since it's no good at serving static assets. Other Ruby 'app servers' aren't also ideal for serving static assets so you'll need to have Rails do that for the meantime. It's not an ideal set-up though since page caching won't work and all requests will hit your app.
Once you use a proper server for serving static assets like Nginx or Apache, you will need to set it to config.serve_static_assets = false so that Rails will leave it to Nginx/Apache to handle serving static assets. That way, not all requests will have to hit your Rails app since caching will work.
Since you're building a Rails engine, you don't need to worry about that since that is the responsibility of the one who is deploying the Rails app. You won't have control over their config.

Why should I use the Asset Pipeline to serve images?

In the Ruby on Rails guide to the Asset Pipeline, it says
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.
http://guides.rubyonrails.org/asset_pipeline.html
To me, this says that images should be kept in the public directory as they can be served statically by my web server and require no pre-processing.
Are there advantages to putting your images in assets/?
Asset precompile appends unique hash value to image filenames, which allows users to get latest version of it despite of cache or expire settings on the server. This is useful when you want to change images in website design.
You don't want to use /assets/images for images what are unlikely to change (like user uploads).
Because it would harm the versatility of the asset pipeline.
With images being served via the asset pipeline, if you change the asset pipeline (for instance, have it upload files to S3) you would have to then sync your images via some other task.
There may be other, deeper reasons, but that is what would give me pause.
EDIT:
Side note: In production thanks to assets:precompile everything from /assets/ will be served from public.

Rails 3 automatic asset deployment to Amazon CloudFront?

Is there a gem or method available in Rails 3.1 that can upload assets to amazon cloud front automatically and use those instead of serving locally hosted ones? I guess it's easy to upload compiled assets manually and then change the rails app config to use that asset host, but when an asset is modified, the uploads to cloud front would need to be done manually again. Any good ways out there for this?
Definitely check out asset_sync on github. Or our Heroku dev centre article on Using a CDN asset Host with Rails 3.1 on Heroku.
There is quite a big performance improvement in using asset_sync vs a CDN custom origin, letting your application lazily compile assets in production or serving them precompiled directly off your app servers. However I would say that. I wrote it.
With asset_sync and S3 you can precompile assets meaning all the assets are there ready to be served on the asset host / CDN immediately
You can only require the :assets bundle in application.rb on precompile, saving memory in production
Your app servers are NEVER hit for asset requests. You can spend expensive compute time on, you know. Computing.
Best practice HTTP cache headers are all set by default
You can enable automatic gzip compression with one extra config
If you use Cloudfronts “Custom origin” option you do not need to upload anything, Cloudfront will fetch the assets from your server when needed. For details of setting this up see:
http://blog.ertesvag.no/post/10720082458
Take a look at https://github.com/rumblelabs/asset_sync - we're using it just to S3 but I guess the CloudFront part is pretty easy once the assets are on S3.
It's ends up being a rake task that you just add to execute in your deployment process.
another option would be https://github.com/moocode/asset_id, the readme has an example to use it with cloudfront.
It should work with rails 3.1 but I have only used it on 3.0.x.
Ss John said all solutions would end up being a rake task + a bit of logic to change the asset path in rails.

Resources