# [Rails4][devise] devise簡易筆記
###### tags: `Rails4`,`devise`
參考資料:
[devise github page](https://github.com/plataformatec/devise)
[getting-started](https://github.com/plataformatec/devise#getting-started)
[如何在既有的user model新增confirmable?](https://github.com/plataformatec/devise/wiki/How-To:-Add-:confirmable-to-Users)
[How to Setup Multiple Devise User Models](https://github.com/plataformatec/devise/wiki/How-to-Setup-Multiple-Devise-User-Models)
stckoverflow:
https://stackoverflow.com/questions/12774488/devise-custom-login-form
https://stackoverflow.com/questions/3546289/override-devise-registrations-controller
<hr>
[Devise](https://github.com/plataformatec/devise)是一個非常熱門的gem套件,主要用於使用者的登入,註冊與驗證,同時也支援第三方登入,像是Google,facebook等等.
## 安裝 & 初始化devise
### 安裝devise gem至rails專案中
```terminal
$ bundle add devise
```
### 初始化產生器
```terminal
$ rails g devise:install
```
### 設定config
config/environments/development.rb
```ruby!
#...
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
#...
```
### 產生devise檔案:以users為例
>以下步驟均假設
>1. 不同使用者種類採用不同的資料表(members,admins,customers...等)
>2. 有針對不同使用者種類客製化不同view需求
>若僅有單一使用者類型需求,可改參考以下連結:
>https://github.com/plataformatec/devise#getting-started
### 修改devise.rb
config/initializers/devise.rb
```ruby
config.scoped_views = true
```
terminal
```terminal
$ rails g devise user
$ rake db:migrate
$ rails g devise:views users
$ rails g devise:controllers users
```
### 設定routes
config/routes.rb
```ruby!
devise_for :users, path: 'users', controllers: { sessions: "users/sessions" }
```
重啟server後即可使用devise.
---
## 常用helper
before_action :authenticate_member!
member_signed_in?
current_member
member_session
> member請替換成devise使用的model名稱
---
## 使用rails console在devise建立新使用者
https://stackoverflow.com/questions/4316940/create-a-devise-user-from-ruby-console
新建使用者(跳過驗證)
```ruby!
User.new({:email => "guy@gmail.com", :password => "111111", :password_confirmation => "111111" }).save(false)
```
>若出現以下錯誤訊息:
>NoMethodError: undefined method `[]' for false:FalseClass
>
>就把(false)拿掉, 用.save就好
新建使用者
```ruby!
User.create!({:email => "guy@gmail.com", :password => "111111", :password_confirmation => "111111" })
```
---
## 新增email驗證
https://github.com/plataformatec/devise/wiki/How-To:-Add-:confirmable-to-Users
基本上就是按照上面的教學走.
心得:
devise.rb要修改
config/initializers/devise.rb
```ruby
# config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
config.mailer_sender = 'mail@twkhjl.com' #<--改成自己的寄件者名稱
# Configure the class responsible to send e-mails.
config.mailer = 'Devise::Mailer' #<--反註解
# Configure the parent class responsible to send e-mails.
config.parent_mailer = 'ActionMailer::Base' #<--反註解
```
---
## 設定讓使用者點擊email驗證連結後直接登入
https://stackoverflow.com/questions/25253039/automatically-sign-in-after-confirm-with-devise
config/routes.rb
```ruby
#...
devise_for :users, controllers: {confirmations: 'users/confirmations'}
#...
```
app/controllers/users/confirmations_controller.rb
```ruby=
#...
def after_confirmation_path_for(resource_name, resource)
sign_in(resource)
users_path
end
```
## 跳過devise的email驗證
https://stackoverflow.com/questions/4316940/create-a-devise-user-from-ruby-console
```ruby=
u = User.new({
email: 'email帳號',
password: '密碼',
password_confirmation: '密碼'
})
u.confirm
u.save
```
---
## 手動寄驗證信給用戶
https://stackoverflow.com/questions/23716878/how-to-manually-send-a-devise-email/23717181
使用rails console示範:
```terminal
$ rails c
$ u=User.first
$ u.send_confirmation_instructions
```
---
## 允許用戶使用email以外的欄位(username等..)登入
https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign_in-using-their-username-or-email-address
https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address
---
## 更改現有用戶的密碼(使用rails console)
https://rubydoc.info/github/plataformatec/devise/master/Devise%2FModels%2FRecoverable:reset_password
```c!
$ u=User.first
$ u.reset_password("123456","123456")
$ u.save
```
## 登出相關
### 登出用戶-手動刪除session
假設使用customer資料表:
```ruby=
session.delete("warden.user.customer.key")
# 底下這行可導向至登入頁面
# 注意要隨資料表名稱不同去修改路徑
redirect_to new_customer_session_path
```
## Routes相關
### 自訂devise網址轉向
https://stackoverflow.com/questions/7974227/how-to-override-devise-redirection
假設使用admin model:
app/controllers/admins/sessions_controller.rb
```ruby=
class Admins::SessionsController < Devise::SessionsController
#...
#自訂註冊成功後要轉向的網址
def after_sign_up_path_for(resource)
admins_path
end
#自訂登入後要轉向的網址
def after_sign_in_path_for(resource)
admins_path
end
#自訂登出後要轉向的網址
def after_sign_out_path_for(resource)
admins_path
end
end
```
### 為不同的使用者table設定不同的root path
```ruby
#...
namespace :admins do
get "/" => "admins#index"
end
namespace :users do
get "/" => "users#index"
end
#...
```
---
## 修改密碼長度
https://github.com/plataformatec/devise/wiki/Customize-minimum-password-length
## 使用i18n
(尚未測試)
https://github.com/tigrish/devise-i18n
devise zh-TW.yml
https://github.com/tigrish/devise-i18n/blob/master/rails/locales/zh-TW.yml
i18n使用方式
https://ihower.tw/rails/i18n.html
> vscode有外掛"Rails i18n"支援i18n的intellisense
---
## 指定不同layout給devise controller
https://github.com/plataformatec/devise/wiki/How-To%3a-Create-custom-layouts
https://stackoverflow.com/questions/11082213/changing-devise-default-layouts
config/initializers/devise.rb
```ruby!
Devise.setup do |config|
#...
Rails.application.config.to_prepare do
Devise::SessionsController.layout proc{|controller|
if resource_name == :admin
"admins/login" if action_name == "new"
else
"admins/application"
end
if resource_name == :user
"users/login" if action_name == "new"
else
"users/application"
end
}
Devise::RegistrationsController.layout "admins/application"
Devise::ConfirmationsController.layout "admins/application"
Devise::UnlocksController.layout "admins/application"
Devise::PasswordsController.layout "admins/application"
end
end
```
## view相關
### 在登入頁面顯示錯誤訊息
https://stackoverflow.com/questions/4112103/devise-not-displaying-error-messge-during-an-authentication-failure
helpers/devise_helper.rb
```ruby!
# https://stackoverflow.com/questions/4112103/devise-not-displaying-error-messge-during-an-authentication-failure
module DeviseHelper
def devise_error_messages!
flash_alerts = []
error_key = 'errors.messages.not_saved'
if !flash.empty?
flash_alerts.push(flash[:error]) if flash[:error]
flash_alerts.push(flash[:alert]) if flash[:alert]
flash_alerts.push(flash[:notice]) if flash[:notice]
error_key = 'devise.failure.invalid'
end
return "" if resource.errors.empty? && flash_alerts.empty?
errors = resource.errors.empty? ? flash_alerts : resource.errors.full_messages
messages = errors.map { |msg| content_tag(:li, msg) }.join
sentence = "錯誤訊息: #{errors.count}"
# sentence = I18n.t(error_key, :count => errors.count,
# :resource => resource.class.model_name.human.downcase)
#加上這一段以避免在第一次進入登入頁面時出現錯誤訊息
if messages.scan(t('devise.failure.unauthenticated')).count <= 0
html = <<-HTML
<div>
<h2>#{sentence}</h2>
<ul>#{messages}</ul>
</div>
HTML
else
html=""
end
html.html_safe
end
end
```
在devise的sign_in form內加上<%=devise_error_messages!%>即可使用此helper
---