I’m working on a site using Spree 0.70, Rails 3.1, and Ruby 1.9. I’ve noticed that some pages are getting rendered without their <html><head></head><body></body></html> blocks.
Instead, Rails appears to be automatically wrapping the page in a <html><body></body></html> block, which means any code intended to be in the head (i.e. CSS includes, the page title block, etc.) shows up inside the body, and anything dependent on attributes of the head or body tags (e.g. CSS) doesn’t work because those elements are missing.
This puzzles me because clearly my layout is being rendered, partials and all, but these top-level elements are being ignored or overridden.
When I say “some pages” I’ve confirmed that it doesn’t happen in the admin pages, and it doesn’t happen in pages confined to my application (i.e. they don’t use the spree_application.html.erb layout and their controller doesn’t subclass Spree::BaseController.) I have overridden the spree_application.html.erb layout by making a copy in my application (I had no choice), and all the pages with this problem use that layout. Could that be a factor? (Here is a page with the broken layout.)
How can I get my root elements back?
ETA: Here’s the file I have in my app at app/views/layouts/spree_application.html.erb. This is the layout which all the pages showing the issue have in common. Note that the div structure is subtly different from the Spree-supplied layout; this is why I need to replace the layout rather than using a Deface override.
<!DOCTYPE HTML>
<%# Overrides the Spree default template %>
<html>
<head data-hook="inside_head">
<%= render 'shared/head' %>
<!--[if lte IE 7]>
<link rel="stylesheet" type="text/css" href="/stylesheets/ie.css" />
<![endif]-->
</head>
<body class="<%= body_class %>" id="<%= @body_id || 'default' %>" data-hook="body">
<div id="page-scroll" data-hook>
<div class='header-wrapper'></div>
<div id="header" data-hook>
<ul id="nav-bar" data-hook>
<%= render 'shared/nav_bar' %>
</ul>
<%= render 'shared/logo' %>
</div>
<div id="wrapper" data-hook>
<%= render 'shared/content' %>
</div>
</div>
<%= render 'shared/footer' %>
<%= render 'shared/google_analytics' %>
</body>
</html>
I resolved this issue by moving the ERb comment out of the
<html>container and into the<head>container. My theory, which I haven’t had time to confirm, is that when Deface is in use (which it is, in Spree) even the ERb templates need to be valid, and having anything other than<head>...</head><body>...</body>containers inside<html></html>is not valid. So either Deface (or Nokogiri, which Deface uses under the hood) is rewriting this to force it to be valid, or it’s stripping those containers and Rails is adding the basic code before output.