I've got an up to date Rails 5 app running Devise, and Action Cable. I can authorize the connection just fine, that is not the problem. The issue is using current_user helper within a notification partial that's pushed out using Action Cable. It's causing an error because no middleware is exec in Action Cable.
TLDR;
current_user helper causing error of missing warden key when used in a partial broadcasted with action cableThis sums it up better than I can. Here's the accompanying link: https://evilmartians.com/chronicles/new-feature-in-rails-5-render-views-outside-of-actions

I've tried a few work arounds and haven't had much luck, and I'm definitely not in the mindset of monkey patching. Any thoughts?
I'm bumping this again after researching on Google how to fix this error, and coming across my own bug report from back in March. I realize you don't get paid to maintain this gem but if you have any thoughts, I'd love to hear them.
Any idea on how to get this fixed? I have tried many things that did not work. Having issue with user_signed_in? as well. Any help or idea on how to fix this will be appreciated.
Hi @bearded-avenger, thank you for reporting this. Sorry for taking this long to reply, I've started to looking into the issues recently and there were a lot of them.
Unfortunately, I haven't worked with Action Cable before, so I'm not sure what would be an ideal solution for this problem.
I'm not sure if I'm missing something. The article suggests to mock a rack env, but if we do, we won't have any real values on it, right?
Let's say that we make #current_user handle the case were warden isn't initialized: what would the method return? nil?
I'm closing this issue because it has not had recent activity.
If you're still facing this on the latest version, please open a new one with all the information requested in the template.
Thank you!
Actually, this is an issue that happens when you want to render a partial outside of your actions...Like in a job, and your partial uses devise helpers (current_user, user_signed_in? etc). This is similar to the following issue: https://github.com/plataformatec/devise/issues/4271
This is still an issue, and yeah the above bug is just like it.
Our app uses notifications. Each notification is in a partial. Each partial has something like current_user.has_read_notification?. Notifications are delivered in real time with action cable. With the way things are now, as you mentioned, there's no way to get a handle on current_user. Passing the user through the partial and doing a lookup isnt an option.
Ideally, we have access to current_user in partials rendered outside of the scope of the app.
@bearded-avenger I just want to know what the ideal solution would be in order to tackle this. I don't have previous experience with action cable or Application.renderer, so I'm a little lost here.
Since no rack middlewares are called, I don't see how we could access the current user. The blog post mentioned above says we should "mock a request". But if that's the case, current_user would always return nil, right? Am I missing something here?
@tegon thanks for popping in and looking into this, I really do appreciate your time. I'm not well versed enough in devise or middleware to give you a good answer to that question yet, but it sounds about right. Perhaps someone else reading this may have some thoughts.
@bearded-avenger oh, ok. Thanks for your reply.
The thing is: we use Warden for authentication. It is a rack middleware that is called in a request and reads the current session to define whether a user is authenticated or not. By reading the previous comments, it seems like in this case, no rack middlewares are called - which is why you're getting this error message. So I'm not sure how we could handle this without any middlewares being called.
I'm going to reopen this to see if anyone else can help.
[ActiveJob] [CommentBroadcastJob] [29558acd-658a-4a3a-b870-f447881740b8] Error performing CommentBroadcastJob (Job ID: 29558acd-658a-4a3a-b870-f447881740b8) from Async(default) in 34.14ms: 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.):
I cannot find any solution for it.
any updates?
I've run into this as well. I'm trying to bring the notifications feature from this app into my own:
https://github.com/gorails-screencasts/gorails-episode-125/
I'm running ActionCable on a separate server (using docker compose) and Apartment for multi-tenancy with subdomain scoped cookies. My action-cable-url was set to ws://lvh.me:28080. It needs the subdomain in there to access the env['warden'] key from a ws:// request. It can be fixed with something like this in your application layout:
- if current_account.present?
-# TODO account for wss protocol for production (wss)
%meta{name: "action-cable-url", content: "ws://#{current_account.subdomain}.lvh.me:28080"}
- else
= action_cable_meta_tag
Or something more graceful that works with the existing action_cable_meta_tag helper.
Hi there,
I'm running a project that uses:
We are using Action Cable, and for authentication using Devise and Warden, we have the following code in the app/channels/connection.rb file.
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
logger.add_tags 'ActionCable', current_user.email
end
protected
def find_verified_user
if verified_user == env['warden'].user
verified_user
else
reject_unauthorized_connection
end
end
end
Hope it helps. Regards.
I'm closing this since it looks like the way to is to manually pass the current user to the views. Because we rely on Warden there must be a rack request in order for it to work.
I was facing the same problem, when I tried to use ApplicationController.render to render the partial view that I want to pass to the action cable.
I've got the solution from the article linked below, but this solution makes sign_in_count increase whenever rendering a partial view using ApplicationController.render_with_signed_in_user.
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
It can be happening when you try to get Devise current_user in some part of code being managed by action cable. like a background job to render comment or something else. you can resolve it by using something like following in your controller, since you cant access warden at a model or job level(according to my limited knowledge): (I call a job right after creation of my comment in CommentsController create action, which calls a private method to render a comment partial containing edit and delete button, for which current_user was required)
def create
@product = Product.find(comment_params[:product_id])
@comment = @product.comments.build(comment_params)
@comment.save!
gon.comment_id = @comment.id
gon.comment_user_id = @comment.user_id
ActionCable.server.broadcast "chat", comment: render_comment
render :create, layout: false
end
def render_comment
CommentsController.renderer.instance_variable_set(:@env, {"HTTP_HOST"=>"localhost:3000",
"HTTPS"=>"off",
"REQUEST_METHOD"=>"GET",
"SCRIPT_NAME"=>"",
"warden" => warden})
CommentsController.render(
partial: 'comments/comment_detail',
locals: {
product: @product,
comment: @comment
}
)
end
this will help you resolve warden issue, if you have used devise's current_user in that partial, it will give you the commentor user (as it should since that user initiated the rendering of partial). Now to solve this, if you have a front end framework you might need to fetch the current user from cookies in order to restrict some actions like edit/delete. but if you are working in pure rails the solution I came across is that you have to make a hidden field in the dom having current users id, and you will fetch that id for comparison in a script. you might need to access rails variables in javascript, for that you can use GON gem. I know this answer might contain much more than asked but I've searched alot and no where I found a satisfactory solution to this problem, feel free to discuss.
env['warden'].user
I found this approach on a lot of places, but for me env['warden'].user is nil.
UPDATE:
I had multiple models configured for authorization, so https://stackoverflow.com/a/49884788/4738391 solved the issue.
Most helpful comment
I'm bumping this again after researching on Google how to fix this error, and coming across my own bug report from back in March. I realize you don't get paid to maintain this gem but if you have any thoughts, I'd love to hear them.