Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access current_user from a Rails Notification?

I'm building an audit trail that needs to know which user is currently making the request. My audit trail is built using ActiveSupport::Notifications to receive an even that needs to be audited.

What I would like to do is use an ActiveSupport::Concern to encapsulate the logic for my audit needs, so that I can easily add auditing to any model in my system.

In general this is easy to do. I even blogged about it a while back. However, I'm having a hard time figuring out how to get the current user that making the request to the web server, so that I can log who is making what changes in my audit trail.

I know there are a ton of questions about "how do I get current_user in my model" but I'm not asking about doing it in a model, so I'm hoping there is a better set of answers. Since my audit code is infrastructure related, I am hoping that there is some way I can tap into the current request that is being processed, or something else that would definitively tell me who is currently logged in / making the request.

I've read a lot of "answers" that say to use thread storage and put the current_user in there. I don't like this answer for many of the reasons that others don't - there is no guarantee that thread storage is safe. it could bleed across multiple requests if the server uses the same thread to process multiple requests, etc.

so... given that I am not trying to access current_user from my model, but rather from either an ActiveSupport::Concern or ActiveSupport::Notifications event subscription, are there any good options for me to know who the current user is?

Update

I'm using devise for authentication, which uses Warden on the back end. devise retrieves the current_user by calling request.env['warden'].authenticate(:scope => :user) (assuming i use a "User" model for authentication).

Is there a way for me to access the current request object from within my concern or notification subscription? Back in my .NET days, I would have been able to call HttpContext.Current.Request and all would be good. What's the equivalent in Rails?

like image 260
Derick Bailey Avatar asked Jun 29 '11 02:06

Derick Bailey


1 Answers

Rails' ActionController::Instrumentation has explicit support for this, using append_info_to_payload.

Add a method to your ApplicationController:

def append_info_to_payload(payload)
  super
  payload[:current_user_id] = current_user.try(&:id)
end

now, when your observer is called back, the information will be in the event.payload:

ActiveSupport::Notifications.subscribe /process_action.action_controller/ do |*args|
  event = ActiveSupport::Notifications::Event.new(*args)
  current_user_id = event.payload[:current_user_id]
  # do something interesting with current_user_id here
end
like image 52
cluesque Avatar answered Nov 03 '22 16:11

cluesque