drapergem / draper

Decorators/View-Models for Rails Applications

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Addition of Draper Gem causes empty string output in ActionController::API requests

synth opened this issue · comments

When we add gem 'draper' to our Gemfile in our Rails 5.0.x project, it breaks our ActionController::API requests by causing an empty string to be returned. I believe this is due to our use of the responders gem as well.

We see the debugger hit the following:

# .rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/responders-2.4.0/lib/action_controller/responder.rb
  184:     def to_format
   185:       if !get? && has_errors? && !response_overridden?
   186:         display_errors
   187:       elsif has_view_rendering? || response_overridden?
=> 188:         default_render
   189:       else
   190:         api_behavior
   191:       end
# .rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/responders-2.4.0/lib/action_controller/responder.rb
   278:     def has_view_rendering?
=> 279:       controller.class.include? ActionView::Rendering
   280:     end

So, has_view_rendering? returns true due to the injection of ActionView::Rendering into the class hierarchy by Draper in the Draper::Compatability::ApiOnly module. This causes the default_render to be called and not the api_behavior which is what we need and see when we don't have the Draper gem in the Gemfile.

The ApiOnly module is run automatically upon gem load to "temporarily" add view_context support to ActionController::API. In the comments it explicitly calls this a "hack" and "temporary solution". If so, there should be a way for developers to opt out of this functionality.

module Draper
module Compatibility
# Draper expects your `ApplicationController` to include `ActionView::Rendering`. The
# `ApplicationController` generated by Rails 5 API-only applications (created with
# `rails new --api`) don't by default. However, including `ActionView::Rendering` in
# `ApplicatonController` breaks `render :json` due to `render_to_body` being overridden.
#
# This compatibility patch fixes the issue by restoring the original `render_to_body`
# method after including `ActionView::Rendering`. Ultimately, including `ActionView::Rendering`
# in an ActionController::API may not be supported functionality by Rails (see Rails issue
# for more detail: https://github.com/rails/rails/issues/27211). This hack is meant to be a
# temporary solution until we can find a way to not rely on the controller layer.
module ApiOnly
extend ActiveSupport::Concern
included do
alias_method :previous_render_to_body, :render_to_body
include ActionView::Rendering
alias_method :render_to_body, :previous_render_to_body
end
end
end
end

It seems like a very bad practice to modify class hierarchies just by adding a gem. Is it possible to add a setting to opt out of this behavior - or better, make it opt-in.

PS. Other than this, love the gem.

I ran into this same exact problem with draper 3.1.0