-
Notifications
You must be signed in to change notification settings - Fork 25
Create a role
In the following command you will replace MODEL
with the class name used for the application’s users (it’s frequently User
but could also be Admin
). This will create a model (if one does not exist) and configure it with the default Devise modules. The generator also configures your config/routes.rb
file to point to the Devise controller.
$ rails generate devise MODEL
Next, check the MODEL for any additional configuration options you might want to add, such as confirmable or lockable. If you add an option, be sure to inspect the migration file (created by the generator if your ORM supports them) and uncomment the appropriate section. For example, if you add the confirmable option in the model, you'll need to uncomment the Confirmable section in the migration.
Then run rails db:migrate
You should restart your application after changing Devise's configuration options (this includes stopping spring). Otherwise, you will run into strange errors, for example, users being unable to login and route helpers being undefined.
you can customize each controller by following these steps:
-
Create your custom controllers using the generator which requires a scope:
$ rails generate devise:controllers [scope]
If you specify
users
as the scope, controllers will be created inapp/controllers/users/
. And the sessions controller will look like this:class Users::SessionsController < Devise::SessionsController # GET /resource/sign_in # def new # super # end ... end
(Use the -c flag to specify a controller, for example:
rails generate devise:controllers users -c=sessions
) -
Tell the router to use this controller:
devise_for :users, controllers: { sessions: 'users/sessions' }
-
Finally, change or extend the desired controller actions.
You can completely override a controller action:
class Users::SessionsController < Devise::SessionsController def create # custom sign-in code end end
Or you can simply add new behaviour to it:
class Users::SessionsController < Devise::SessionsController def create super do |resource| BackgroundWorker.trigger(resource) end end end
This is useful for triggering background jobs or logging events during certain actions.
And you can create your custom controllers using the generator which requires a scope:
$ rails generate devise:controllers [scope]
Tell the router to use this controller, you can add devise:controllers you want.
devise_for :users, controllers: { sessions: 'users/sessions' }
You can completely override a controller action:
class Users::SessionsController < Devise::SessionsController
def create
# custom sign-in code
end
end
Or you can simply add new behaviour to it:
class Users::SessionsController < Devise::SessionsController
def create
super do |resource|
BackgroundWorker.trigger(resource)
end
end
end
You should restart your application after changing Devise's configuration options (this includes stopping spring). Otherwise, you will run into strange errors, for example, users being unable to login and route helpers being undefined.
Devise also ships with default routes. If you need to customize them, you should probably be able to do it through the devise_for method. It accepts several options like :class_name, :path_prefix and so on, including the possibility to change path names for I18n:
devise_for :users, path: 'auth', path_names: { sign_in: 'login', sign_out: 'logout', password: 'secret', confirmation: 'verification', unlock: 'unblock', registration: 'register', sign_up: 'cmon_let_me_in' }
If you have the need for more deep customization, for instance to also allow "/sign_in" besides "/users/sign_in", all you need to do is create your routes normally and wrap them in a devise_scope
block in the router:
devise_scope :user do
get 'sign_in', to: 'devise/sessions#new'
end
This way, you tell Devise to use the scope :user
when "/sign_in" is accessed. Notice devise_scope
is also aliased as as
in your router.
Please note: You will still need to add devise_for
in your routes in order to use helper methods such as current_user
.
devise_for :users, skip: :all
Devise will create some helpers to use inside your controllers and views. To set up a controller with user authentication, just add this before_action (assuming your devise model is 'User'):
before_action :authenticate_user!
For Rails 5, note that protect_from_forgery
is no longer prepended to the before_action
chain, so if you have set authenticate_user
before protect_from_forgery
, your request will result in "Can't verify CSRF token authenticity." To resolve this, either change the order in which you call them, or use protect_from_forgery prepend: true
.
If your devise model is something other than User, replace "_user" with "_yourmodel". The same logic applies to the instructions below.
To verify if a user is signed in, use the following helper:
user_signed_in?
For the current signed-in user, this helper is available:
current_user
You can use the sign_in
and sign_out
methods on your controller tests:
sign_in @user
sign_in @user, scope: :admin
If you are testing Devise internal controllers or a controller that inherits from Devise's, you need to tell Devise which mapping should be used before a request. This is necessary because Devise gets this information from the router, but since controller tests do not pass through the router, it needs to be stated explicitly. For example, if you are testing the user scope, simply use:
it 'GET new' do
# Mimic the router behavior of setting the Devise scope through the env.
@request.env['devise.mapping'] = Devise.mappings[:user]
# Use the sign_in helper to sign in a fixture `User` record.
sign_in users(:alice)
get :new
# assert something
end