A common way to add custom behavior after user login is to subclass Devise’s SessionsController and override the necessary actions. This approach is flexible and keeps the custom logic separate from the Devise setup.
1. Update your routes to point to the custom sessions controller:
# config/routes.rb devise_for :users, controllers: { sessions: "custom_sessions" }
2. Create a new sessions controller:
# app/controllers/custom_sessions_controller.rb class CustomSessionsController < Devise::SessionsController before_action :before_login, only: :create after_action :after_login, only: :create private def before_login # Add custom logic to execute before login (optional). end def after_login # Add custom logic to execute after login, e.g., creating a directory. create_user_directory unless directory_exists? end def create_user_directory # Example implementation user_dir = Rails.root.join("user_data", current_user.username) FileUtils.mkdir_p(user_dir) unless Dir.exist?(user_dir) end def directory_exists? Dir.exist?(Rails.root.join("user_data", current_user.username)) end end
3. Test the changes by logging in and verifying that the custom code is executed.
Devise is built on top of Warden, which provides callbacks to execute code during authentication events. This approach integrates directly into Devise's lifecycle without overriding controllers.
1. Add the Warden callback in devise.rb:
# config/initializers/devise.rb Warden::Manager.after_authentication do |user, auth, opts| # Custom logic after login Rails.logger.info "User #{user.email} logged in at #{Time.now}" # Check and create directory for the user user_dir = Rails.root.join("user_data", user.username) FileUtils.mkdir_p(user_dir) unless Dir.exist?(user_dir) end
2. Restart your Rails server to apply the changes.
Notes:
Another approach is to hook into Rails’ ActiveSupport::Notifications to handle post-login events. This keeps the custom logic modular and independent of Devise’s implementation.
1. Add the notification in sessions_controller.rb:
# app/controllers/custom_sessions_controller.rb class CustomSessionsController < Devise::SessionsController after_action :notify_login_event, only: :create private def notify_login_event ActiveSupport::Notifications.instrument("user.logged_in", user: current_user) end end
2. Create a subscriber for the event:
# config/initializers/login_subscriber.rb ActiveSupport::Notifications.subscribe("user.logged_in") do |name, start, finish, id, payload| user = payload[:user] Rails.logger.info "User #{user.email} logged in!" # Check and create directory for the user user_dir = Rails.root.join("user_data", user.username) FileUtils.mkdir_p(user_dir) unless Dir.exist?(user_dir) end
Devise provides built-in hooks like after_sign_in_path_for that can be customized to execute specific logic.
1. Override after_sign_in_path_for in ApplicationController
# app/controllers/application_controller.rb class ApplicationController < ActionController::Base protected def after_sign_in_path_for(resource) # Custom logic after login create_user_directory(resource) unless directory_exists?(resource) super end private def create_user_directory(user) user_dir = Rails.root.join("user_data", user.username) FileUtils.mkdir_p(user_dir) unless Dir.exist?(user_dir) end def directory_exists?(user) Dir.exist?(Rails.root.join("user_data", user.username)) end end
2. This method allows you to handle logic seamlessly after login without altering session controllers or Warden directly:
Each approach serves a unique purpose based on your app's structure and needs:
Test each solution and choose the one that aligns best with your application's architecture and maintenance strategy.