LoginSignup
11
10

More than 1 year has passed since last update.

Devise使用時のApplicationController.renderer.renderで発生するDevise could not find the `Warden::Proxy` instance on your request environment

Last updated at Posted at 2019-01-24

はじめに

Warden::Proxyまわりのエラーを調べてたら、日本語の記事ではRSpecでの記事しか見つからなかったので投稿。
また、この記事は以下のサイトを参考にしております。ちなみに、こちらのサイトではDeviseだけでなく、Clearanceについても言及されています。
Using Rails 5 new renderer with Clearance and Devise

#ActionView::Template::Errorエラー
ApplicationController.renderer.renderを呼び出した際に下記のエラーが発生。

ActionView::Template::Error (Devise could not find the Warden::Proxy instance on your request environment.Make sure that your application is loading Devise and Warden as expected and that the Warden::Manager middleware is present in your middleware stack.
If you are seeing this on one of your tests, ensure that your tests are either executing the Rails middleware stack or that your tests are using the Devise::Test::ControllerHelpers module to inject the request.env['warden'] object for you.):

##原因
Rails5のActionController::Rendererを使用して独自のプロキシを定義せずに通常のコントローラーとは別フローで、テンプレートをレンダリングするようです。
そのため、Deviseでの認証に必要なコントローラー環境全体とミドルウェアにアクセスできず、エラーが発生します。

Rendering partials with the new Rails 5 ActionController::Renderer provides a nice shortcut to render templates outside the normal controller flow without defining own proxy classes. This is useful for a variety of use cases, like pushing partials down a MessageBus pipe to frontend or mobile, or PDF generation with WicketPDF.
But to access authentication stuff, like Clearance/Devise (current_user) or CanCan (current_ability) is not obvious, as the whole controller environment and middlewares are missing.
Using Rails 5 new renderer with Clearance and Devise

##対策
ApplicationControllerに、renderer.renderの代替メソッドを用意します。

app/controllers/application_controller.rb
def self.render_with_signed_in_user(user, *args)
   ActionController::Renderer::RACK_KEY_TRANSLATION['warden'] ||= 'warden'
   proxy = Warden::Proxy.new({}, Warden::Manager.new({})).tap{|i| i.set_user(user, scope: :user) }
   renderer = self.renderer.new('warden' => proxy)
   renderer.render(*args)
 end

呼び出す際は、ApplicationController.renderer.render(変更前)の代わりにApplicationController.render_with_signed_in_user(変更後)を呼び出します。

# 変更前
ApplicationController.renderer.render('messages/message', locals: { post: @post })
# 変更後
ApplicationController.render_with_signed_in_user(user, 'posts/post', locals: { post: @post })

##参考サイト
今回の記事に載せた対策について
Using Rails 5 new renderer with Clearance and Devise

Renderについて
Render views outside of action

11
10
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10