draper icon indicating copy to clipboard operation
draper copied to clipboard

Run controller filter to `activate_draper` as early as possible

Open bf4 opened this issue 9 years ago • 1 comments

Fixes #640

I haven't figured out how to fix this deterministically in the Draper code, yet, but here's a breakdown of the issue and the fix, so hopefully someone can make a PR.

This is on Draper 2.1.0, Rails 4.2.5.1, Ruby 2.2.

  1. When going to /users/sign_in we were getting a NoMethodError undefined method 'host' for nil:NilClass
  2. This is because the h.request was returning nil
  3. This is because the view context proxy controller is set in a way that mocks the controller and request when Draper::ViewContext.controller is nil. Draper::ViewContext.controller || ApplicationController.new. https://github.com/drapergem/draper/blob/v2.1.0/lib/draper/view_context/build_strategy.rb#L39-L42
  4. Draper::ViewContext.controller is set in the controller by the callback before_filter :activate_draper https://github.com/drapergem/draper/blob/v2.1.0/lib/draper.rb#L36
  5. That means, that any before_action filters that 1) use draper and 2) run before the active_draper callback won't have the controller context set

The specific callbacks we had running was Devise::SessionController#after_sign_in_path_for and the code fix was:

def after_sign_in_path_for(user)
+    # Draper before filter to set controller context hasn't run yet
+    activate_draper
  user.decorate.sign_in_path
end

where the UserDecorator#sign_in_path was calling h.rails_admin.dashboard_path.

I tried futzing with changing the Draper filter to prepend_before_action :activate_draper, but that didn't work, so I went with the fix above and made this issue :)

It's possible we may want to modify the initializer to run earlier via :after => 'action_controller.set_configs' as below, but I haven't tried it.

  initializer "draper.setup_action_controller", :after => 'action_controller.set_configs' do |app|
      ActiveSupport.on_load :action_controller do
        Draper.setup_action_controller self
      end
    end

    initializer "draper.setup_action_mailer", :after => 'action_controller.set_configs' do |app|
      ActiveSupport.on_load :action_mailer do
        Draper.setup_action_mailer self
      end
    end

bf4 avatar Feb 10 '16 17:02 bf4

@codebycliff, confirmed this also happens in v3 with Rails 5. Still haven't found an after or before hook that works though.

chuck-john avatar Apr 10 '17 03:04 chuck-john