###ログイン機能を作る
####そのためにコントローラを作る
ubuntu:~/environment/my_app (basic-login) $ rails generate controller Sessions new
Running via Spring preloader in process 15621
create app/controllers/sessions_controller.rb
route get 'sessions/new'
invoke erb
create app/views/sessions
create app/views/sessions/new.html.erb
invoke test_unit
create test/controllers/sessions_controller_test.rb
invoke helper
create app/helpers/sessions_helper.rb
invoke test_unit
invoke assets
invoke scss
create app/assets/stylesheets/sessions.scss
####ログイン機能のためのルーティング
config/routes.rb
Rails.application.routes.draw do
get 'sessions/new'
root 'static_pages#home'
get '/signup', to: 'users#new'
# signupのurlを入力してuser/newのアクションが動き、htmlが表示される。
get '/login', to: 'sessions#new' <-
# newアクション
post '/login', to: 'sessions#create' <-
# creteアクション
delete '/logout', to: 'sessions#destroy' <-
# destroyアクション
resources :users
# ユーザー情報を表示するURL(/users/1)を追加するためだけのものではありません
# ユーザーのURLを生成するための多数の名前付きルートと共に、
# アクションが利用できるようになるのです
end
####セッションにアクションできることをアクセスすることを
test/controllers/sessions_controller_test.rb
require 'test_helper'
class SessionsControllerTest < ActionDispatch::IntegrationTest
test "should get new" do
get login_path
# 新しいセッションのページ(ログイン)をgetする
assert_response :success
# getリクエストが成功したか確認
end
end
####そしてセッションページを作成
<% provide(:title, "Log in") %>
<h1>ログイン</h1>
<!--セッションページ-->
<div class="row">
<div class="col-md-6 col-md-offset-3">
<%= form_with(url: login_path, scope: :session, local: true) do |f| %>
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
<%= f.submit "Log in", class: "btn btn-primary" %>
<% end %>
<p>New user? <%= link_to "Sign up now!", signup_path %></p>
</div>
</div>
####そこからログイン機能をつける
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])
# ユーザーログイン後にユーザー情報のページにリダイレクトする
# 有効且つパスワードを認識する
else
flash.now[:danger] = 'Invalid email/password combination' # 本当は正しくない
# エラーメッセージを作成する
#.nowで何かすると消えるようにする
render 'new'
end
end
def destroy
# セッションの削除(ログアウト)
end
end
####統合テストのファイルを生成
ubuntu:~/environment/my_app (basic-login) $ rails generate integration_test users_login
Running via Spring preloader in process 4690
invoke test_unit
create test/integration/users_login_test.rb
####ログインのテストを書く
test/integration/users_login_test.rb
require 'test_helper'
class UsersLoginTest < ActionDispatch::IntegrationTest
test "login with invalid information" do
get login_path
# /loginとリクエストする
assert_template 'sessions/new'
# loginページが表示されていることを確認
post login_path, params: { session: { email: "", password: "" } }
# 無効なデータでログインさせる
assert_template 'sessions/new'
# そうするとログインページに戻らせる
assert_not flash.empty?
# エラーメッセージが表示されるか確認
get root_path
# .comと入力し、リクエストする
assert flash.empty?
# ホーム画面に行くとエラーメッセージが消えているか確認
end
end
####ApplicationコントローラにSessionヘルパーモジュールを読み込む
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
include SessionsHelper
# どのコントローラでも使えるようにする
end
####ログインさせるメソッド
app/helpers/sessions_helper.rb
module SessionsHelper
# 渡されたユーザーでログインする
def log_in(user)
session[:user_id] = user.id
# sessionはログインを表す
end
end
####ユーザーをログインさせる
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
# ログインさせる
redirect_to user
# user_url(user)を表す
# プロフィールページへのルーティングにしています。
else
flash.now[:danger] = 'Invalid email/password combination' # 本当は正しくない
# エラーメッセージを作成する
#.nowで何かすると消えるようにする
render 'new'
end
end
def destroy
# セッションの削除(ログアウト)
end
end
####現在ログイン中のユーザーとする
module SessionsHelper
# 渡されたユーザーでログインする
def log_in(user)
session[:user_id] = user.id
# sessionはログインを表す
end
# 現在ログイン中のユーザーを返す(いる場合)
def current_user
if session[:user_id]
# sessionsに含まれるなら
@current_user ||= User.find_by(id: session[:user_id])
# それを検索し、絵ログイン中のユーザーcurrent_userとする
end
end
end
####ログイン中であるかないかでレイアウトを変更する
<header class="navbar navbar-fixed-top navbar-inverse">
<div class="container">
<%= link_to "自作アプリ", root_path, id: "logo" %>
<nav>
<ul class="nav navbar-nav navbar-right">
<li><%= link_to "Home", root_path %></li>
<% if logged_in? %>
<!--ログイン中だったら-->
<li><%= link_to "Users", '#' %></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
Account <b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li><%= link_to "Profile", current_user %></li>
<!--リンク ユーザーページを表示させる-->
<li><%= link_to "Settings", '#' %></li>
<li class="divider"></li>
<li>
<%= link_to "Log out", logout_path, method: :delete %>
<!--ログアウトのリンクもつける-->
</li>
</ul>
</li>
<% else %>
<!--ログインしていなかったら-->
<li><%= link_to "Log in", login_path %></li>
<!--ログインしていなかったらログインページに移動させる-->
<% end %>
</ul>
</nav>
</div>
</header>
####パスワードをハッシュ化させる
app/models/user.rb
class User < ApplicationRecord
.
.
.
# 渡された文字列のハッシュ値を返す
def User.digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST :
BCrypt::Engine.cost
# コストパラメータはテストでは最小にする
BCrypt::Password.create(string, cost: cost)
# stringはハッシュ化する文字列
# cost ハッシュ化する計算コストを表す
end
end
####ユーザーログインのテストで使うfixture
michael:
# テストデータ
name: Michael Example
email: michael@example.com
password_digest: <%= User.digest('password') %>
####ユーザーログインをテストする
require 'test_helper'
class UsersLoginTest < ActionDispatch::IntegrationTest
def setup
# テストユーザー
@user = users(:michael)
end
test "login with invalid information" do
get login_path
# /loginとリクエストする
assert_template 'sessions/new'
# loginページが表示されていることを確認
post login_path, params: { session: { email: "", password: "" } }
# 無効なデータでログインさせる
assert_template 'sessions/new'
# そうするとやり直しのページに戻らせる
assert_not flash.empty?
# エラーメッセージが表示されるか確認
get root_path
# .comと入力し、リクエストする
assert flash.empty?
# ホーム画面に行くとエラーメッセージが消えているか確認
end
end
###ユーザー登録時にログイン
####ユーザー登録中にログインする
app/controllers/users_controller.rb
.
.
.
def create
@user = User.new(user_params) # 実装は終わっていないことに注意!
if @user.save
# 保存の成功をここで扱う。
log_in @user
# インスタンス変数に変更し、ユーザーページに移動させる
flash[:success] = "ようこそ自作アプリへ成功しました!"
redirect_to @user
# 表示させるユーザーページを
else
render 'new'
end
end
.
.
.
####テスト中のログインステータスを論理値で返すメソッド
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'
class ActiveSupport::TestCase
# Run tests in parallel with specified workers
parallelize(workers: :number_of_processors)
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# テストユーザーがログイン中の場合にtrueを返す
def is_logged_in?
!session[:user_id].nil?
# ログイン中であるかどうかを検索中
end
# Add more helper methods to be used by all tests here...
end
####テストユーザーを使い、ログインのテスト
test/integration/users_signup_test.rb
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
.
.
.
test "valid signup information" do
get signup_path
# サインアップページへアクセスする
assert_difference 'User.count', 1 do
# ユーザーが一つ追加された
post users_path, params: { user: { name: "Example User",
email: "user@example.com",
password: "password",
password_confirmation: "password" } }
# 有効な情報を登録
end
follow_redirect!
# POSTリクエストを送信した結果を見て、指定されたリダイレクト先に移動するメソッド
assert_template 'users/show'
assert is_logged_in?
# ログイン中であるか?
end
end
####ログアウトメソッドを作る
app/helpers/sessions_helper.rb
module SessionsHelper
.
.
.
# 現在のユーザーをログアウトする
def log_out
session.delete(:user_id)
# sessionからidを削除する
@current_user = nil
# ログイン済みのユーザーを空にする
end
end
####そのメソッドを使い、ログアウトの一連の流れを入力する
app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
.
.
.
def destroy
# セッションの削除(ログアウト)
log_out
# sessions_helperでメソッドから使う
# セッションとログインを削除する
redirect_to root_url
# 削除した後 ホーム画面に戻る
end
end
require 'test_helper'
class UsersLoginTest < ActionDispatch::IntegrationTest
def setup
# テストユーザー
@user = users(:michael)
end
test "login with valid email/invalid password" do
# ログインをするまでの過程をチェック
get login_path
# 名前付きルートでログイン画面に行く
assert_template 'sessions/new'
# 要求されたログイン画面が表示されたか?
post login_path, params: { session: { email: @user.email,
password: "invalid" } }
# ログイン画面に無効なテストデータを入力
assert_not is_logged_in?
# test_helper ログイン中でない
assert_template 'sessions/new'
# 失敗したらまたログインページが表示されるか?
assert_not flash.empty?
# flashメッセージは表示されたか?
get root_path
# ホーム画面に行くことを要求する?
assert flash.empty?
# flashメッセージは表示されなかったか?
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'
# ユーザーページが表示されているか?
assert_select "a[href=?]", login_path, count: 0
# ログイン済みなのでログインリンクが表示されないか?
assert_select "a[href=?]", logout_path
# その代わりログアウトリンクが表示されているか?
assert_select "a[href=?]", user_path(@user)
#
delete logout_path
assert_not is_logged_in?
assert_redirected_to root_url
follow_redirect!
assert_select "a[href=?]", login_path
assert_select "a[href=?]", logout_path, count: 0
assert_select "a[href=?]", user_path(@user), count: 0
end
end