As an admin, there are times you want to see exactly what another user sees. Meet Pretender.
- Easily to switch between users
- Minimal code changes
- Plays nicely with Action Cable and auditing tools
💥 Rock on
Pretender is flexible and lightweight - less than 100 lines of code :-)
Works with any authentication system - Devise, Authlogic, and Sorcery to name a few.
🍊 Battle-tested at Instacart
Add this line to your application’s Gemfile:
gem'pretender'And add this to your ApplicationController:
classApplicationController < ActionController::Baseimpersonates:userendSign in as another user with:
impersonate_user(user)
The current_user method now returns the impersonated user.
You can access the true user with:
true_user
And stop impersonating with:
stop_impersonating_userCreate a controller
classUsersController < ApplicationControllerbefore_action:require_admin!# your authorization methoddefindex@users=User.order(:id)enddefimpersonateuser=User.find(params[:id])impersonate_user(user)redirect_toroot_pathenddefstop_impersonatingstop_impersonating_userredirect_toroot_pathendendAdd routes
resources:users,only: [:index]dopost:impersonate,on: :memberpost:stop_impersonating,on: :collectionendCreate an index view
<ul><%@users.eachdo |user| %><li>Sign in as <%=link_touser.name,impersonate_user_path(user),method: :post%></li><%end%></ul>And show when someone is signed in as another user in your application layout
<% if current_user != true_user %>
You (<%= true_user.name %>) are signed in as <%= current_user.name %><%= link_to "Back to admin", stop_impersonating_users_path, method: :post %><% end %>If you keep audit logs with a library like Audited, make sure it uses the true user.
Audited.current_user_method=:true_userAnd add this to your ApplicationCable::Connection:
moduleApplicationCableclassConnection < ActionCable::Connection::Baseidentified_by:current_user,:true_userimpersonates:userdefconnectself.current_user=find_verified_userreject_unauthorized_connectionunlesscurrent_userendprivatedeffind_verified_userenv["warden"].user# for DeviseendendendThe current_user method now returns the impersonated user in channels.
Pretender is super flexible. You can change the names of methods and even impersonate multiple roles at the same time. Here’s the default configuration.
impersonates:user,method: :current_user,with: ->(id){User.find_by(id: id)}Mold it to fit your application.
impersonates:account,method: :authenticated_account,with: ->(id){EnterpriseAccount.find_by(id: id)}This creates three methods:
true_accountimpersonate_accountstop_impersonating_accountEveryone is encouraged to help improve this project. Here are a few ways you can help:
- Report bugs
- Fix bugs and submit pull requests
- Write, clarify, or fix documentation
- Suggest or add new features