テクノロジー

2017年1月8日

login_02

認証の仕組みを理解する

それでは今までの内容を踏まえて、実際にログイン機能を実装します。
実装方法を確認してみましょう。

まずはログインのフローを確認していきます。

https://diveintocode.gyazo.com/ac0e4b7950a41baa56858553162ed593

これを図解すると以下のようになります。これで認証が終わったらクッキーとセッションを使ってログインしているユーザーの情報を保持する動きがなされるのです。

https://diveintocode.gyazo.com/dbcd6c03852e8b1c906a72d45d21ca58

一方で、ログアウトのフローはこのような感じです。

https://diveintocode.gyazo.com/57a6bb21bb6bd7ba5a2db8f25001754c

ログイン機能を実装する

いよいよログイン機能を実装していきます。

【手順】ルーティングを定義する

[config/routes.rb]

resources :sessions, only: [:new, :create, :destroy]

【手順】セッションコントローラを作成する

bin/rails g controller sessions

【手順】createアクションを実装する

[app/controllers/sessions_controllers.rb]

def create
  user = User.find_by(email: params[:session][:email].downcase)
  if user && user.authenticate(params[:session][:password])
    log_in(user)
    current_user
    redirect_to root_path, notice: 'ログインしました'
  else
    flash.now[:alert] = 'メールアドレスまたはパスワードが間違っています'
    render 'new'
  end
end

createアクションでは以下4つの役割があります。

  1. emailをキーにしてユーザーをDBから取り出す
  2. authenticateメソッドでパスワードが一致しているかを確認する
  3. SessionStoreにuser_idというキーの名前で該当するユーザーのidを格納する
  4. current_userに該当のユーザを格納する

1と2に関してはアクション内にベタ書きしますが、3は

log_in(user)

4は

current_user

というメソッドをセッションヘルパーに定義します。

【手順】log_inというメソッドをヘルパーに定義する

[app/helpers/sessions_helper.rb]

def log_in(user)
  session[:user_id] = user.id
end

【手順】current_userというメソッドをヘルパーに定義する

[app/helpers/sessions_helper.rb]

def current_user
  if session[:user_id].present?
    @current_user ||= User.find_by(id: session[:user_id])
  end
end

【手順】destroyアクションを実装する

[app/controllers/sessions_controllers.rb]

def destroy
  log_out if logged_in?
  redirect_to root_path, notice: 'ログアウトしました'
end

destroyアクションでは以下2つの役割があります。

  1. SessionStoreに格納されているuser_idの中身をnilにする
  2. current_userの中身をnilにする

1と2に関しては

log_out(user)

というメソッドをセッションヘルパーに定義します。

【手順】log_outというメソッドをヘルパーに定義する

[app/helpers/sessions_helper.rb]

def log_out
  session.[:user_id] = nil
  @current_user = nil
end

さらにログインしているかどうかをチェックするメソッドを定義しておきましょう。
これはログインしているユーザーがnil、つまりcurrent_userがnilでなければtrueが返り、ログインしているとみなされます。

【手順】ログインしているかどうかをチェックできるメソッドを実装する

[app/helpers/sessions_helper.rb]

def logged_in?
  !current_user.nil?
end

【手順】newアクションを実装する

先ほどlogged_in?というメソッドを実装したのでそれを元にnewアクションを実装しましょう。
すでにログインしていた場合にトップ画面にリダイレクトさせるコードを実装します。

[app/controllers/sessions_controllers.rb]

def new
  if logged_in?
    redirect_to root_path, notice: 'すでにログインしています。'
  end
end

【手順】usersコントローラのnewアクションを修正する

前回の実装のままでは、ログインしているユーザーでもサインアップが可能になってしまうので、ログインしているユーザーの時はトップ画面へリダイレクトさせます。

def new
  unless logged_in?
    @user = User.new
  else
    redirect_to root_path, notice: 'すでにログインしています。'
  end
end

【手順】ログイン画面を実装する

[app/views/sessions/new.html.erb]

<h1>ログイン</h1>

<%= notice %><%= alert %>

<%= form_for(:session, url: sessions_path) do |f| %>
  <div class="field">
    <%= f.label :email %>
    <%= f.email_field :email %>
  </div>

  <div class="field">
    <%= f.label :password %>
    <%= f.password_field :password %>
  </div>

  <div class="aciton">
    <%= f.submit "ログイン" %>
  </div>
<% end %>

<p><%= link_to "ユーザー登録へ", new_user_path %></p>

【手順】トップ画面を実装する

ログインしている時とログインしていない時で表示するリンクを分岐させましょう。これもlogged_in?というメソッドを利用して実装します。

[app/views/top/index.html.erb]

<h1>トップ画面</h1>
<%= notice %>

<% if logged_in? %>
  <li><%= link_to "プロフィール", current_user %></li>
  <li><%= link_to "ログアウト", session_path(current_user), method: "delete" %></li>
    </ul>
  </li>
<% else %>
  <li><%= link_to "ログイン画面へ", new_session_path %></li>
  <li><%= link_to "ユーザ登録", new_user_path %></li>
<% end %>

【手順】セッションの持続時間を設定する

最後にセッション持続時間を設定しましょう。ここを設定してあげないと、ブラウザを閉じた時にセッションが破棄されてしまいます。

[config/session_store.rb]

Rails.application.config.session_store :cookie_store, key: '(アプリ名)_session', expire_after: 15.minutes

【手順】サーバーを立ち上げる

bin/rails s

以上でログイン機能の実装は全て完了しました。
いかがでしたでしょうか?普段Deviseを使っていてログインの仕組みを理解していなかったら、この機会にぜひ理解していきましょう!

DIVE INTO CODEのことをもっと知ってみませんか?