jbuilder icon indicating copy to clipboard operation
jbuilder copied to clipboard

No rendering in 5.1

Open msimonborg opened this issue 7 years ago • 4 comments

After upgrading my Rails API-only app to 5.1 from ~> 5.0.0 I immediately had issues rendering my Jbuilder templates. The response body would just be blank: ""

I am also using the latest version of Jbuilder

Googling around I found that I was not the only person having this issue. One person suggested an easy fix that worked:

class ApplicationController < ActionController::API
  include ActionView::Rendering
  ...
end

Making sure that one Module was included fixed the problem. Poking around the Jbuilder source code I found some relevant lines in the jbuilder/railtie.rb

class Jbuilder
  class Railtie < ::Rails::Railtie
    initializer :jbuilder do

      ...

      if Rails::VERSION::MAJOR >= 5
        module ::ActionController
          module ApiRendering
            include ActionView::Rendering
          end
        end

        ActiveSupport.on_load :action_controller do
          if self == ActionController::API
            include ActionController::Helpers
            include ActionController::ImplicitRender
          end
        end
      end
    end

    ...

  end
end

This initializer hook should include the needed module in ApiRendering, which is included in ActionController::API. This makes sense from an ancestry POV as opposed to including directly into ActionController::API, and it probably works most of the time, but for whatever reason it's not working for me and a bunch of other people, maybe because of some other configuration or dependency. It seems that since the same initializer hook is including other modules directly into ActionController::API, we could do that for ActionView::Rendering, like this:

class Jbuilder
  class Railtie < ::Rails::Railtie
    initializer :jbuilder do

      ...

      if Rails::VERSION::MAJOR >= 5
        # module ::ActionController
        #   module ApiRendering
        #     include ActionView::Rendering
        #   end
        # end

        ActiveSupport.on_load :action_controller do
          if self == ActionController::API
            include ActionController::Helpers
            include ActionController::ImplicitRender
            include ActionView::Rendering
          end
        end
      end
    end

    ...

  end
end

I tried out this change locally in my app's gem source code and it works. I also wrote a simple test that checks if the module is included after calling Jbuilder::Railtie.run_initializers, and the tests pass both the old way and the new way. Unfortunately the old way doesn't work for everyone it seems, this seems more surefire.

msimonborg avatar Jul 11 '17 05:07 msimonborg

Isn't that normal ? Isn't ActionController::API made so that it's skips a a lot of view rendering inclusion in the controller since it's not supposed to render html ? (which means, no view folder).

wouldn't it be better to convert your view with ActiveModel::Serializers ?

nekogami avatar Oct 24 '17 07:10 nekogami

I personally prefer using Jbuilder over ActiveModel::Serializers. It's a little simpler to maintain different serializations for different rails actions. I'm running into the same problem where when using ActionController::API, the json response is empty. But if I include: include ActionView::Rendering, it starts to work correctly.

Using rails 5.1.6.

vsai avatar Apr 16 '18 04:04 vsai

I am also experiencing this or a related issue (it provoked a stack-overflow question) where I was successfully rendering with 5.1.6, but once I started including AccessGranted gem, ActionView::Rendering no longer appears in my ancestry tree for my controller. I'm not enough of a ruby expert to say why the include logic may be changing here, but as far as the class definition goes, the only other change to ancestry is inclusion of AccessGranted::Rails::ControllerMethods.

Your fix above does work for me, however it also seems to introduce complications for controllers with actions that aren't supposed to render with jbuilder.

update

I was able to determine that the gem causing me trouble was loading ActionController::API at file load time (https://github.com/chaps-io/access-granted/blob/master/lib/access-granted.rb#L11-L21), which I believe caused relevant classes to be loaded before Jbuilder could patch ApiController as identified by @msimonborg . For myself I was able to solve this by submitting a PR to that gem which moves that loading logic into a rail tie, but that may not be affordable to all users of Jbuilder.

ships avatar Apr 18 '18 16:04 ships

Looks like duplicate #346

gsmetal avatar May 11 '18 15:05 gsmetal