jbuilder
jbuilder copied to clipboard
No rendering in 5.1
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.
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 ?
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.
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.
Looks like duplicate #346