Q:

Conditional layout and action caching without a layout

I have an action on a controller where I'm using action caching. However I'm using the layout: false flag on that caching call since my layout has user dependent information like login status. This works perfectly.
Then I was adding the pjax-rails gem, which basically adds this code to the controller:
layout ->(c) { pjax_request? ? false : 'application' }

That is on some requests the layout isn't rendered. Now I (kinda logically) want to combine these two approaches together.
However when pjax_request? == true I get this error:

There was no default layout for MyController

What am I doing wrong and how can I solve this problem?

PS: This is easiest reproducible in this case:
class MyController < ApplicationController
  layout false
  caches_action :index, :layout => false

  def index
  end
end

A:

I almost think this might be a bug in Rails. Check out this block of code around line 143 of actionpack/lib/action_controller/caching/actions.rb:
body = controller.read_fragment(cache_path.path, @store_options)

unless body
  controller.action_has_layout = false unless @cache_layout
  yield
  controller.action_has_layout = true
  body = controller._save_fragment(cache_path.path, @store_options)
end

body = controller.render_to_string(:text => body, :layout => true) unless @cache_layout

controller.response_body = body

It looks like it's correctly rendering the body without a layout in the first unless block, but then it's forcing the template to render with a layout as part of the response body. And if you look at the stack trace, that's the line that leads to the exception.
I manually edited the file to :layout => @cache_layout (which always evaluates to :layout => false since it's guarded by an unless) and the view rendered as expected.
I'm not sure what you could do about this other than temporarily patch that file yourself and open a bug report. I might also be wrong about the behavior of that line, but it certainly looks like the culprit.

