Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
synth opened this issue Jul 31, 2019 · 3 comments
Assignees

Comments

@synth
Copy link

synth commented Jul 31, 2019

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.

@diegous
Copy link

diegous commented Nov 27, 2020

I ran into this same exact problem with draper 3.1.0

@Alexander-Senko
Copy link
Collaborator

Alexander-Senko commented Sep 4, 2024

I hope, I could find a way not to include ActionView::Rendering into ActionController::API 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants