# [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 ---