Conditionally Including Resources on SSL or non-SSL to Avoid Mixed Content Security Warnings in Ruby on Rails
When building content that can be delivered on an encrypted HTTPS connection it is necessary to reference all of the embedded resources, 3rd party badge images, embedded YouTube videos, etc, from an HTTPS url. Otherwise a mixed content error will imply to your users that the website is not safe, ouch!
For instance, consider this YouTube video reference:
<iframe height="349" src="https://www.youtube.com/embed/P3LaGQciUXs?hl=en&fs=1" width="425"></iframe>
This works great when the page is loaded either over an SSL or a non-SSL connection. The trouble is that the encrypted resource can take longer to load than a non-SSL resource because the user’s browser has to negotiate a new encrypted connection with the third party server. When the security is needed this is good. When it is not, this just increases the chance that the user will go away and never come back (How Loading Time Affects Your Bottom Line) - especially on a mobile device.
In a Ruby on Rails view, you can use the
request.ssl? flag to conditionally supply either a https or a http for the external website reference, like this:
<%= request.ssl? ? "https://" : "http://" %>
In your Ruby HTML view (or partial) it would look something like this:
<iframe height="349" src="<%= request.ssl? ? "https://" : "http://" %>www.youtube.com/embed/P3LaGQciUXs?hl=en&fs=1" width="425"></iframe>
With that the video will be included as
http:// on an non-SSL page and as
https:// on an SSL page.
However, there is an even better way that does not require a ternary operator in your view. While researching for this post I came across the protocol-relative URL reference in HTML (hat tip to Paul Irish).
The trick works like this:
<img src="//domain.com/img/logo.png" />
The same video could be included with:
<iframe height="349" src="//www.youtube.com/embed/P3LaGQciUXs?hl=en&fs=1" width="425"></iframe>
The only downside is that this might not work reliably in Internet Explorer 6. If you care about IE6, you have to use the ternary conditional server-side code in your Rails HTML template.