“Remember me” checkbox

最後,我們要來完成 Remember me 的 checkbox 功能了。架構如下:

首先,先在表單架構裡增加 checkbox 的 layout,如同文字、密碼和 email 欄位,checkbox 也可以使用 Rails 的輔助方法來建構:

<%= f.label :remember_me, class: "checkbox inline" do %>
  <%= f.check_box :remember_me %>
  <span>Remember me on this computer</span>
<% end %>

app/views/sessions/new.html.erb 加上 checkbox 的架構:

app/views/sessions/new.html.erb

<% provide(:title, "Log in") %>
<h1>Log in</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <%= form_for(:session, url: login_path) do |f| %>

      <%= f.label :email %>
      <%= f.email_field :email, class: 'form-control' %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :remember_me, class: "checkbox inline" do %>
        <%= f.check_box :remember_me %>
        <span>Remember me on this computer</span>
      <% end %>

      <%= f.submit "Log in", class: "btn btn-primary" %>
    <% end %>

    <p>New user? <%= link_to "Sign up now!", signup_path %></p>
  </div>
</div>

然後撰寫 checkbox 的樣式:

app/assets/stylesheets/custom.css.sass

.
.
.
/* forms */
.
.
.
.checkbox
  margin-top: -10px
  margin-bottom: 10px
  span
    margin-left: 20px
    font-weight: normal

#session_remember_me
  width: auto
  margin-left: 0

最後畫面會長這樣:

這個 checkbox 的功能就是如果勾選它,就記住使用者,反之就不要記住。因為我們之前的準備工作都做好了,所以現在只要一行程式碼就可以解決。提交表單的時候,params hash 會多一個 checkbox(remember_me) 的值:

session: !ruby/hash:ActionController::Parameters
  email: ''
  password: ''
  remember_me: '1'

如果勾選了 checkbox,params[:session][:remember_me] 的值會是 1,反之為 0

所以我們可以檢查 params hash 中相關的值,根據提交的值決定要不要記住使用者:

if params[:session][:remember_me] == '1'
  remember(user)
else
  forget(user)
end

也可以寫成一行,這種寫法是透過三元運算子(ternary operator):

params[:session][:remember_me] == '1' ? remember(user) : forget(user)

把這個判斷述句加進 Sessions controller 裡的 create action:

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_in user
      params[:session][:remember_me] == '1' ? remember(user) : forget(user)
      redirect_to user
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render 'new'
    end
  end

  def destroy
    log_out if logged_in?
    redirect_to root_url
  end
end

三元運算子 - ternary operator

一般的 control flow 是這樣寫:

if boolean?
  do_one_thing
else
  do_something_else
end

但使用三元運算子,可以寫成這樣:

boolean? ? do_one_thing : do_something_else

也可以執行賦值,例如:

if boolean?
  var = foo
else
  var = bar
end

可以寫成這樣:

var = boolean? ? foo : bar

在函式中也常用三元運算子回傳值:

def foo
  do_stuff
  boolean? ? "bar" : "baz"
end