Finding and authenticating a user

跟建立使用者註冊的步驟一樣,我們會先處理提交無效的(invalid)表單資料。先分析提交表單之後會發生什麼事,然後在登入失敗時顯示有幫助的錯誤訊息,以此為基礎,再繼續處理登入成功的情況。

現在來設定 Sessions controller 的 create action,使用 render 渲染 new 頁面,然後加上 destroy action:

app/controllers/sessions_controller.rb

class SessionsController < ApplicationController

  def new
  end

  def create
    render 'new'
  end

  def destroy
  end
end

現在瀏覽 /login ,並按下送出:

下面的 debug 訊息顯示出,按下送出之後,會產生 params hash,email 和密碼都在 sessions key 裡面:

sessions: !ruby/hash:ActionController::Parameters
  email: ''
  password: ''
commit: Log in
controller: sessions
action: create

params hash 是一個巢狀 hash:

{ session: { password: "foobar", email: "[email protected]" } }

也就是說:

params[:session]

其實就是在讀取 session 這個 key 的值,而這個值是個 hash:

{ password: "foobar", email: "[email protected]" }

所以,要取得 email 跟密碼就是:

params[:session][:email]
params[:session][:password]

也就是說,在 create action 中,params hash 已經包含驗證使用者的 email 和密碼資訊。而實際上我們也已經有了以下方法:

  • Active Record 提供的 User.find_by 方法
  • has_secure_password 提供的 authenticate 方法,這個方法會在驗證失敗時回傳 false

以下是完整的程式碼:

app/controllers/sessions_controller.rb

class SessionsController < ApplicationController

  def new
  end

  def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      # Log the user in and redirect to the user's show page.
    else
      # Create an error message.
      render 'new'
    end
  end

  def destroy
  end
end

這行:

user = User.find_by(email: params[:session][:email].downcase)

透過提交的 email ,來取出在資料庫裡對應的使用者,因為之前我們讓 email 存進資料庫前都轉成小寫,因此這裡加上 downcase 方法,確保可以比對到正確的資料。

這行是 Rails 慣用的語法:

user && user.authenticate(params[:session][:password])

使用 && 來檢查使用者是否存在以及密碼是否正確。因為除了 nilflase,其他物件都為 true。上述程式碼可能會發生的結果如下表:

User Password a && b
使用者不存在 anything (nil && [anything]) == false
使用者存在 wrong password (true && false) == false
使用者存在 right password (true && true) == true