0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Laravel で Ruby on Rails チュートリアル【8章】ログイン

Last updated at Posted at 2020-11-14

環境

  • Laravel 8.6
  • PHP 8.0
  • Bootstrap 5.1

8.1 セッション

8.1.1 Sessionsコントローラ

ログイン処理とログアウト処理

/app/Http/Controllers/SessionsController.php
class SessionsController extends Controller
{
    public function create()
    {
        return view("sessions.create");
    }
}
/routes/web.php
Route::get('login', [SessionsController::class, 'create'])->name('login');
Route::post('login', [SessionsController::class, 'store']);
Route::delete('logout', [SessionsController::class, 'destroy'])->name('logout');
/tests/Unit/SessionsControllerTest.php
class SessionsControllerTest extends TestCase
{
    public function testGetCreate()
    {
        $response = $this->get(route("login"));
        $response->assertStatus(200);
    }
}

8.1.2 ログインフォーム

/resources/views/sessions/create.blade.php
@extends('layouts.application')

@section('title', 'Log in')

@section('content')
    <h1>Log in</h1>

    <div class="row">
        <div class="col-md-6 offset-md-3">
            {{ Form::open(['route' => 'login']) }}

            <div class="mb-3">
                {{ Form::label('email', 'Email', ['class' => 'form-label fw-bold']) }}
                {{ Form::text('email', "", ["class" => "form-control"]) }}
            </div>

            <div class="mb-3">
                {{ Form::label('password', 'Password', ['class' => 'form-label fw-bold']) }}
                {{ Form::password('password', ["class" => "form-control"]) }}
            </div>

            {{ Form::submit("Log in", ["class" => "btn btn-primary w-100"]) }}
            {{ Form::close() }}

            <p>New user? {{ Html::link(route("signup"), "Sign up now!") }}</p>
        </div>
    </div>
@endsection

8.1.3 ユーザーの検索と認証

/app/Http/SessionsController.php
    public function store(Request $request)
    {
        $user = User::where("email", Str::lower($request->email))->first();
        if ($user && Hash::check($request->password, $user->password)) {
            // ログイン後にユーザー情報のページにリダイレクトする
        } else {
            // エラーメッセージを作成する
            return back()->withInput();
        }
    }

8.1.4 フラッシュメッセージを表示する

/app/Http/Controllers/SessionsController.php
session()->flash('message', ['danger' => 'Invalid email/password combination']);

8.1.5 フラッシュのテスト

/tests/Feature/UsersLoginTest.php
    public function testInvalidLogin()
    {
        $response = $this->get(route('login'));
        $response->assertViewIs('sessions.create');
        $response = $this->followingRedirects()
            ->post('login', [
                'email'    => "",
                'password' => "",
            ]);
        $response->assertViewIs('sessions.create');
        $response->assertSeeText('Invalid email/password combination');
        $response = $this->get('/');
        $response->assertDontSeeText('Invalid email/password combination');
    }

8.2 ログイン

8.2.1 log_inメソッド

/app/Http/Controllers/SessionsController.php
    public function store(Request $request)
    {
        $user = User::where("email", Str::lower($request->email))->first();
        if ($user && Hash::check($request->password, $user->password)) {
            Auth::login($user);
            return redirect()->route("users.show", $user);
        } else {
            session()->flash('message', ['danger' => 'Invalid email/password combination']);
            return back()->withInput();
        }
    }

8.2.2 現在のユーザー

Auth::user();

8.2.3 レイアウトリンクを変更する

/resources/views/layouts/header.blade.php
<header>
    <nav class="navbar navbar-expand fixed-top navbar-dark bg-dark p-0">
        <div class="container">
            {{ link_to_route('home', "sample app", [], ["id" => "logo", "class" => "navbar-brand"]) }}
            <ul class="navbar-nav">
                <li class="nav-item">{{ link_to_route("home", "Home", [], ["class" => "nav-link"]) }}</li>
                <li class="nav-item">{{ link_to_route("help", "Help", [], ["class" => "nav-link"]) }}</li>
                @if (auth()->check())
                    <li class="nav-item">{{ link_to_route("users.index", "Users", [], ["class" => "nav-link"]) }}</li>
                    <li class="dropdown">
                        <a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown">Account</a>
                        <ul class="dropdown-menu">
                            <li>{{ link_to_route("users.show", "Profile", [auth()->id()], ["class" => "dropdown-item"]) }}</li>
                            <li>{{ link_to_route("home", "Settings", [], ["class" => "dropdown-item"]) }}</li>
                            <li>
                                <hr class="dropdown-divider">
                            </li>
                            <li>
                                <a href="javascript:document.logoutform.submit()" class="dropdown-item">Log out</a>
                                {{ Form::open(["route" => "logout", "method" => "delete", "name" => "logoutform"]) }}
                                {{ Form::close() }}
                            </li>
                        </ul>
                    </li>
                @else
                    <li>{{ link_to_route("login", "Log in", [], ["class" => "nav-link"]) }}</li>
                @endif
            </ul>
        </div>
    </nav>
</header>

8.2.4 レイアウトの変更をテストする

/database/seedes/TestSeeder.php
class TestSeeder extends Seeder
{
    public function run()
    {
        DB::table('users')->insert([
            'name' => "Michael Example",
            'email' => strtolower("michael@example.com"),
            'password' => bcrypt('password'),
            'created_at' => Carbon::now(),
            'updated_at' => Carbon::now(),
        ]);
    }
}
/tests/Feature/UsersLoginTest.php
class UsersLoginTest extends TestCase
{
    private $user;
    private $user_pass;

    protected function setUp()
    {
        parent::setUp();
        Artisan::call('migrate:fresh');
        $this->seed('TestSeeder');
        $this->user = User::find(1);
        $this->user_pass = "password";
    }
...
    public function testValidLogin()
    {
        $this->get(route("login"));
        $response = $this->followingRedirects()
                        ->post(route("login"), [
                            'email'    => $this->user->email,
                            'password' => $this->user_pass
                        ]);
        $response->assertViewIs('users.show');
        $dom = $this->dom($response->content());
        $this->assertSame(0, $dom->filter('a:contains("Log in")')->count());
        $this->assertSame(route("logout"), $dom->filter('form[name="logoutform"]')->attr("action"));
        $this->assertSame(route("users.show", $this->user), $dom->filter('a:contains("Profile")')->attr("href"));
    }
}
/tests/Feature/UsersSignupTest.php
class UsersSignupTest extends TestCase
{
    protected function setUp(): void
    {
        parent::setUp();
        Artisan::call('migrate:fresh');
    }

テストで使用するDBを指定する

/phpunit.xml
        <server name="DB_CONNECTION" value="sqlite"/>
        <server name="DB_DATABASE" value=":memory:"/>

8.2.5 ユーザー登録時にログイン

/app/Http/Controllers/UsersController.php
    public function store(Request $request)
    {
        $request->email = Str::lower($request->email);
        $request->validate([
            "name"                  => "required|max:50",
            "email"                 => "required|max:255|email|unique:users|email",
            "password"              => "required|confirmed|min:6",
            "password_confirmation" => "required|min:6",
        ]);
        $user = new User;
        $user->name = $request->name;
        $user->email = $request->email;
        $user->password = bcrypt($request->password);
        $user->save();
        Auth::login($user);
        session()->flash("message", ['success' => 'Welcome to the Sample App!']);
        return redirect()->route("users.show", $user);
    }

テスト追加

/tests/Feature/UsersSignupTest.php
$this->assertTrue(Auth::check());

8.3 ログアウト

/app/Http/Controllers/SessionsController.php
    public function destroy()
    {
        Auth::logout();
        return redirect("/");
    }
/tests/Feature/UsersLoginTest.php
    public function testValidLoginToLogout()
    {
        $this->get(route("login"));
        $response = $this->followingRedirects()
                        ->post(route("login"), [
                            'email'    => $this->user->email,
                            'password' => $this->user_pass
                        ]);
        $this->assertTrue(Auth::check());
        $response->assertViewIs('users.show');
        $dom = $this->dom($response->content());
        $this->assertSame(0, $dom->filter('a:contains("Log in")')->count());
        $this->assertSame(route("logout"), $dom->filter('form[name="logoutform"]')->attr("action"));
        $this->assertSame(route("users.show", $this->user), $dom->filter('a:contains("Profile")')->attr("href"));
        $response = $this->followingRedirects()->delete(route("logout"));
        $this->assertFalse(Auth::check());
        $response->assertViewIs("static_pages.home");
        $dom = $this->dom($response->content());
        $this->assertSame(route("login"), $dom->filter('a:contains("Log in")')->attr("href"));
        $this->assertSame(0, $dom->filter('form[name="logoutform"]')->count());
        $this->assertSame(0, $dom->filter('a:contains("Profile")')->count());
    }

8.4 最後に

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?