3

Hey, I want to use Devise and acts_as_audited together but when I try and link them using -

class ApplicationController < ActionController::Base
 audit Candidate
 protected

 def current_user
   @user = User.find(user_session)    
 end

I get this error.

stack level too deep

Do I need to do it differently ?

Thanks

Alex
  • 6,205
  • 7
  • 43
  • 53

4 Answers4

6

This is an old question, but still rears its ugly head. Here's a different, possibly more appropriate workaround which worked for me.

First, as others describe, the bug happens when using audited (formerly acts_as_audited) with devise (and potentially other authentication gems), and then when you are auditing any of the column Devise uses on your User model (last_sign_in_at, last_sign_in_ip, etc).

  1. Devise tries to authenticate the user (using its authenticate_user! before_filter).
  2. Devise tries to update/save the user's sign in info (last_sign_in_at, ip, etc) for posterity
  3. As part of that save, Audited then tries to create an audit for that change.
  4. Audited tries to set the User for that Audit, to indicate who made the change. How does it do that?
  5. Audited calls current_user, a Devise method. Devise isn't yet done with its authenticate method from step 1 - Audited stepped in and is doing its thing. So,
  6. The current_user method repeats step #1 (the authenticate_user! method), creating an infinite loop
  7. Your application errors with Stack Level Too Deep

@DGM's workaround simply tells Audited to not audit this change, which might work for you. However, in my application, I need to audit that change.

Audited allows you to specify a different method to use for current_user.

In application controller, add your new method, referring to the current_user instance variable.

def my_cool_method
    @current_user
end

And then, in config/initializers/audited.rb, tell Audited to use your new method:

Audited.current_user_method = :my_cool_method

With this change, Audited will still audit the change, but it will not try to set the audit's user (the person who made the change) - that will be nil.

Another advantage of this change over the alternate solution by DGM is that we aren't overriding Devise's current_user method, which is similar to monkey patching in that it could cause unintended consequences later.

MrDerp
  • 1,014
  • 2
  • 12
  • 17
  • One comment: I haven't nailed down why this happens sporadically. If anyone every figures that out, I'd love to know. – MrDerp Jan 12 '15 at 21:37
1

Just to close this off.

stack level too deep is caused because devise has built in auditing on the current_user variable.

So every time you access the variable it causes an infinite loop.

Alex
  • 6,205
  • 7
  • 43
  • 53
1

Further explaining - acts_as_audited calls current_user before checking what to ignore, and if current_user triggers a table change, calls an audit again, poof. Infinite loop.

My workaround with the same problem with authlogic is to disable auditing while setting up the session:

def current_user
  return @current_user if defined?(@current_user)
  User.without_auditing do
    @current_user = current_user_session && current_user_session.user
  end
  @current_user
end

However, I still hit some other callbacks that I'd rather not hit. This is authlogic's problem, not act_as_audited's.

Ultimately, I would prefer that the auditing done by devise or authlogic do so in a manner that bypassed validations, callbacks, and timestamps.

DGM
  • 26,629
  • 7
  • 58
  • 79
0

Same thing happens with Authlogic alone. Solution is to add the :except argument with the following fields(see below). Perhaps something similar will work with Devise as well.

# Define explicitly otherwise "Stack Level Too Deep"

acts_as_audited :except => [ :persistence_token,
:perishable_token, :login_count,
:failed_login_count,
:last_request_at, :current_login_at, :last_login_at, :current_login_ip,
:last_login_ip ]

seanbehan
  • 1,463
  • 15
  • 23
  • this doesn't work with authlogic, as I explain below. The exception code takes place after the infinite recursion. – DGM Jul 11 '11 at 21:21