Rails - How to override devise SessionsController to perform specific tasks when user signs in?

Using Devise to manage users sessions / registrations I would need to perform specific tasks (updating some fields in the users table for this specific user for example) each time a user signs in, and before he gets redirected by devise to the home page for connected users.

Do I have to override devise SessionsController, and if yes, how?


Solution 1:

Alternatively, you can create your own sessions controller

class SessionsController < Devise::SessionsController
  def new
    super
  end

  def create
    self.resource = warden.authenticate!(auth_options)
    set_flash_message(:notice, :signed_in) if is_navigational_format?
    sign_in(resource_name, resource)
    if !session[:return_to].blank?
      redirect_to session[:return_to]
      session[:return_to] = nil
    else
      respond_with resource, :location => after_sign_in_path_for(resource)
    end
  end
end

And in routes.rb add:

devise_for :users, controllers: {sessions: "sessions"}

Solution 2:

If you look at Devise's implementation of sessions_controller#create, you'll notice that they yield if you pass a block.

So, just subclass their sessions controllers and pass a block when you call super. To do that, first tell Devise in routes.rb that you'd like to use your own sessions controller:

devise_for :users, controllers: { sessions: 'users/sessions' }

And then create a SessionsController class and pass a block when you call super in your create method. It would look something like this:

# app/controllers/users/sessions_controller.rb

class Users::SessionsController < Devise::SessionsController
  layout "application"
  
  # POST /login
  def create
    super do |user|
      if user.persisted?
        user.update(foo: :bar)
      end
    end
  end
end

Most of the Devise controller methods accept a block, so you could do this for registration, forgot password, etc as well.