What can I serve from CDN for a Rails application? - ruby-on-rails

I have a Ruby on Rails application where the views are contained in .html.erb files. If I introduce a CDN into the deployment pipeline, does that mean the CDN will only be able to serve up static assets such as JS, CSS and images? Will the html still be delivered from the Rails server? Serving the html from the Rails server seems like it will make page load times slower than if I could serve them from the CDN as well.
Thanks!

Related

Can I share my CSS with another application when using asset pipeline?

I am using Rails asset pipeline in a rails 4.x web app. In production I use a CDN (cloudfront) to serve the CSS.
My other application is a non-rails app, but it shares the same CSS as my Rails app.
Is there a way for my other application to use the CSS generated by my rails application?
The problem I am having is that since rails generates a random guid for the filename there is no way for me to reference it in my other application.
e.g.
https://abcd.cloudfront.net/assets/application-asdf23409usdflu34uasdf.css
Update
If I can get the value I can potentially expose the CSS URL as an API endpoint, is that possible?
When you deploying your application and precompiling assets, the task also generates a manifest-md5hash.json that contains a list with all your assets and their respective fingerprints. It looks like:
{"files":{"application-723d1be6cc741a3aabb1cec24276d681.js":{"logical_path":"application.js","mtime":"2013-07-26T22:55:03-07:00","size":302506, "digest":"723d1be6cc741a3aabb1cec24276d681"}, etc...}
You can transfer this file to another application and get correct filenames with guids from it.

How do I know my whole app is Rails Asset Pipeline Compliant?

I am trying to figure out where my issue is for when I try to use aws cloudfront to render the rails assets. Not sure if there is a tool that will determine if my whole app is rails asset pipeline compliant (whether it meets its standards, etc). Any help would be appreciated, even helping me figure out how do I know for sure that my assets are coming from CloudFront and not from my app.
Here's a good tutorial to do that
https://ruby.awsblog.com/post/Tx3VS6Q2Q2K0LJR/Caching-the-Rails-Asset-Pipeline-with-Amazon-CloudFront
You can tell if serving your assets from cloudfront worked or not by viewing the page source of your production environment and see where are your css and js files served from, if it's working you'll find something like this
<link data-turbolinks-track="true" href="http://your-distribution-url.cloudfront.net/assets/application-bfe54945dee8eb9f51b20d52b93aa177.css" media="all" rel="stylesheet" />
Or if you configured a domain for your assets cdn.myapp.com for example you'll find that the assets are served from it
---------------- Update -----------------
Generally you want to organize your assets first before moving them on to a CDN, for the img tag it doesn't matter if you use image_tag or not what matters is the url of the image; if it's an asset image (that can be found in app/assets/images for example use the asset_url helper so that it is served through your asset pipeline (that doesn't apply to you application's images like user profile images).
Also in your CSS files when you use assets (background images for example) use the asset-url helper to get the image through asset pipeline.
Also it's a bad practice to add javascript into your views because you won't be able to server this javascript from your assets pipeline, try to have all your javascript in separate js or coffescript files and use the "Unobtrusive Javascript" practice (more about that in this answer What's the best way to embed a small chunk of javascript in Rails?).

Angular + .nghaml template: Referencing Precompiled Image Assets

I'm using .nghaml for my templates and using the following gems for Angular integration:
gem 'angularjs-rails'
gem 'angular-rails-templates'
My Rail view layouts are name.html.haml and using image_tag within them works fine. On production I can see the images.
In contrast, in my Angular templates (assets/template) with their .nghaml extension I can not use Rails helper image_tag and a direct reference does not work
%image(src="assets/sample_image.png")
The direct reference works locally, but on production images don't render.
This person (Rails Image assets in Angular Directive and template) had a similar issue, but using
%img(ng-src='assets/sample_image.png')
worked locally but not in production. And attempting to use image-url results in the error of undefined method (just as image_tag) because none of the Rails helpers seem to be working in the .nghaml extension.
The images that are working (Rails views with image_tag helpers) are referencing the precompiled assets which have their names changed with the addition of a md5-hash (based on the first linked article), but I'm having issues figuring out how to tell the nghaml templates what the new precompiled assets are called without a Rails helper method.
I ran into this issue with helpers a few months ago (Rails App to Angular: HAML + Rails Helpers) and didn't find a solution, but only recently needed to get images into nghaml templates rather than just creating what I needed with CSS.
I'm currently planning to just move the angular templates back to erb if I can't get this figured out, but if there are alternatives (or solutions) I'm unaware of, I'd love to hear them.
The solution proposed in the post Rails App to Angular: HAML + Rails Helpers will allow you to use the helpers (including the image_tag helper) in your haml files when generating the client-side html files.
One issue: According to the official repo for the angular-rails-template library, the .nghaml extension is no longer supported. You have to rename it to .haml
The bigger issue is that you're using Rails to serve a single-page JS app. There's no need for this, you can serve the site using nginx or Apache and control the caching and do cache busting there (nginx & apache cache busting tutorial)
If you're using Rails for the REST API, it should be de-coupled from your frontend AngularJS app.
If you're trying to do some fancy stuff in the templates aside from the cache busting, you should be doing it in JS and plain HTML. It's weird and strange but AngularJS and other frontend MVC/MVVM frameworks are different beasts compared to Rails and Django and the server-side MVC frameworks.

Rails 4 Asset Pipeline: Asset missing fingerprint in asset_path from js

I am deploying a Rails 4.0 application which includes HTML partial templates as assets for our front-end javascript framework. Although these templates are part of the asset pipeline and are properly precompiled, when I call asset_path from embedded ruby in our js files, it returns the path to our templates without the fingerprint.
I am quite certain that this is purely a Asset Pipeline question, but to give you a complete sense of our tech stack: We use Rails 4.0, Ruby 2.1, AngularJS for our front-end MVC framework, and AssetSync to synchronize our assets between Rails and our CDN.
An example of where this occurs (in a file included in app/assets/application.js.erb:
$routeProvider
.when('/', {
templateUrl: "<%= asset_path 'home.html' %>",
controller: "HomeController"
});
This works great locally, but as soon as config.assets.digest = true in production, the call to asset_path does not properly factor in the fingerprint. The templates are in the app/assets directory within a new subdirectory templates. So in the above example, the home.html asset is at app/assets/templates/home.html. Our javascript has itself been precompiled at that point, so I'm thinking that it might be an issue of which order the assets are precompiled in.
I've noticed a few issues on the Rails Github (1, 2, 3) and a couple of SO posts about fingerprints not being set properly (1, 2), but can't find anything about them not being included at all...
Any help or ideas that you can provide would be much appreciated.
Edit 4/15: forgot to include that the extensions on my application javascript file DOES include .erb (app/assets/application.js.erb). Thanks Alex for catching that. I've updated it above.
Also, following instructions in this article on Heroku, I confirmed that running puts helper.asset_path("home.html") from within a Rails console running in production prints a properly fingerprinted URL for that asset.
This appears to be an issue with the AssetSync gem. I removed it, reconfigured the app so that Rails serves the assets, and the fingerprinting works fine.
If anyone else finds this question and is running into the same issue, I would recommend against using AssetSync. According to Heroku:
Many developers make use of Amazon’s S3 service for serving static assets that
have been uploaded previously, either manually or by some form of build process.
Whilst this works, this is not recommended as S3 was designed as a file storage
service and not for optimal delivery of files under load. Therefore, serving
static assets from S3 is not recommended.
Amazon CloudFront is the preferred method of serving assets through a CDN, and is very easy to configure with a Rails app that serves its own static assets, accomplishing the same goals as AssetSync.
I'm pretty new to this stuff, but to get the asset_path to work, don't you need a .erb on the end of that file?
Check out the bottom of this article for more info:
https://devcenter.heroku.com/articles/rails-4-asset-pipeline
If it works in development, that may not help. There is a helpful section on debugging at the bottom of the article though.
Update
Here's another article that could help:
https://medium.com/self-directed-learning/9ba1f595102a
Flipping on this configuration in Heroku made some of my asset pipeline problems go away:
heroku labs:enable user-env-compile -a yourapp
Hope this helps!
Alex

In rails 3.1 mountable engine app all the css and js are loaded for each request. won't that degrade the performance or be inefficient?

When I look at the source of any of my views generated in rails 3.1 mountable engine, I see all css and javascripts loaded. Isn't that inefficient? Wouldn't it be more efficient that I load the css and js which I need for that particular page?
Are you in the development environment? In production, all of your assets will be compressed and precompiled, so that only application.js and application.css are linked. This is the best way, because the js and css for your whole site is loaded into the browser cache, so that when visiting different pages, it doesn't have to make a bunch of extra server requests.

Resources