これまでのあらすじ
最近SNSを見ていて思うのですが、Railsチュートリアルって何週もするものなのでしょうか?あれって『ゲームとかで言う「強くてニューゲーム」みたいなことをやっているだけなのでは?』って思うのですよ。みなさんは一度クリアしたゲームを「強くてニューゲーム」で何週もするんですか?僕は……。
めっちゃそういう周回プレイ大好き。圧倒的なパワーで蹂躙するのたまらねぇぜ!!
はい、もはやあらすじの体をなしてないRailsチュートリアル第八章はーじめるよー!!前回は登録の方の制御を作りました。今回はログインの方の制御をつくっていきます。あ、こんなこと書いてますけどRailsチュートリアル2週目記事とか書く気はないです。第一章の段階からおふざけプレイで色々やってるからね。二週目の追加要素は書ける気がしないのです。
ログインフォームをつくるよ
今回はセッションの扱いとかの話なんですかね?まあ、何はともあれまずはログイン用のガワを作ります。
# $ rails generate controller Sessions new $ rails generate controller [コントローラ名] [アクション]
そんでこんなの作りました。ログイン時はアカウント情報を表示するようになりました。
Bootstrap4にしてるせいでレイアウトの修正は破壊的になりますね(笑)……。
<!-- app/views/layouts/_header.html.erb 一部抜粋 --> <% if logged_in? %> <li class="nav-item ml-2"><%= link_to "Users", '#', class: "text-light" %></li> <div class="dropdown"> <a href="#" class="dropdown-toggle text-light" data-toggle="dropdown"> Account <b class="caret"></b> </a> <div class="dropdown-menu"> <a class="dropdown-item"><%= link_to "Profile", current_user, class: "ml-2 text-dark" %></a> <a class="dropdown-item"><%= link_to "Settings", '#', class: "ml-2 text-dark" %></a> <a class="divider"></a> <a class="dropdown-item"><%= link_to "Log out", logout_path, method: :delete, class: "ml-2 text-dark" %></a> </div> </div> <% else %> <li class="nav-item ml-2"><%= link_to "Log in", login_path, class: "text-light" %></li> <% end %>
以下作成したソース。
コントローラ
# app/controllers/sessions_controller.rb class SessionsController < ApplicationController # get '/login', to: 'sessions#new' def new end ### ユーザーログイン後にユーザー情報のページにリダイレクト ### ログインできない場合は、エラーメッセージを表示 # post '/login', to: 'sessions#create' def create user = User.find_by(email: params[:session][:email].downcase) if user && user.authenticate(params[:session][:password]) log_in user redirect_to user else flash.now[:danger] = 'Invalid email/password combination' render 'new' end end ### ユーザーログアウト後にセッション情報を削除しホームへリダイレクト # delete '/logout', to: 'sessions#destroy' def destroy log_out redirect_to root_url end end
ヘルパー
module SessionsHelper # 渡されたユーザーでログインする def log_in(user) session[:user_id] = user.id end # 現在ログイン中のユーザーを返す (いる場合) def current_user if session[:user_id] @current_user ||= User.find_by(id: session[:user_id]) end end # ユーザーがログインしていればtrue、その他ならfalseを返す def logged_in? !current_user.nil? end # 現在のユーザーをログアウトする def log_out session.delete(:user_id) @current_user = nil end ### 備考 ### app/controllers/application_controller.rb ### include SessionsHelper end
ルーティングのコメントは後付けですがコントローラの方にちょろちょろコメント付けたからヘルパーとコントローラをいったきたりしなくてすんだ。ところで風の噂の情報なんですけど、「有償IDE使うと自分で作った処理も補完してくれるようになるってきいたんですけどマジですか?」さいつよじゃん。
んでテストの方は以下の通り。
# ログイン系の結合テスト作成
$ rails generate integration_test users_login
# test/integration/users_login_test.rb 一部省略 require 'test_helper' class UsersLoginTest < ActionDispatch::IntegrationTest def setup @user = users(:michael) end test "login with invalid information" do get login_path assert_template 'sessions/new' post login_path, params: { session: { email: "", password: "" } } assert_template 'sessions/new' assert_not flash.empty? get root_path assert flash.empty? end test "login with valid information followed by logout" do get login_path post login_path, params: { session: { email: @user.email, password: 'password' } } assert is_logged_in? assert_redirected_to @user follow_redirect! assert_template 'users/show' delete logout_path assert_not is_logged_in? assert_redirected_to root_url follow_redirect! end end
assert_select
はタグ拾ってこれるかのチェックだし省略。こうやって雑なテストを書くからレイアウトも雑になるんだろうね(白い目)。
第八章の感想
セッションのいじり方を学ぼうということでログインとログアウトができるようになりました。とりあえず「fixture」の使い方とかが勉強になった。内容としては短いですがそんな感じです。
次回はハッテン的ログイン機構だそうです。楽しみですね。
つづく……。
参考: fixture
fixtures - リファレンス - - Railsドキュメント