環境
- Laravel 8.6
- PHP 8.0
- Bootstrap 5.1
7.1 ユーザーを表示する
7.1.1 デバッグとRails環境
デバッグ用のパッケージを追加
sail composer require barryvdh/laravel-debugbar --dev
7.1.2 Usersリソース
artisan tinkerでユーザー作成
User::create(["name" => "Michael Hartl", "email" => "mhartl@example.com", "password" => bcrypt("foobar")]);
ユーザーを表示するページを作成
routes/web.php
Route::resource('users', UsersController::class)->except(["create"]);
/resources/views/users/show.blade.php
{{ $user->name }}, {{ $user->email }}
/app/Http/Controllers/UsersController.php
public function show(User $user)
{
return view('users.show')->with('user', $user);
}
7.1.3 debuggerメソッド
7.1.4 Gravatar画像とサイドバー
ユーザー表示ページ修正
/resources/views/users/show.blade.php
@extends('layouts.application')
@section('title', $user->name)
@section('content')
<h1>
<img src="{{ gravatar_url($user) }}" class="gravatar" alt="Example User">
{{ $user->name }}
</h1>
@endsection
/app/helpers.php
if (!function_exists('gravatar_url')) {
function gravatar_url(User $user)
{
$gravatar_id = md5(strtolower($user->email));
return $gravatar_url = "https://secure.gravatar.com/avatar/{$gravatar_id}";
}
}
ユーザーのメールアドレスを更新
$ sail artisan tinker
>>> User::find(1)->update(["name" => "Example User", "email" => "example@railstutorial.org", "password" => bcrypt("foobar")]);
演習
if (!function_exists('gravatar_url')) {
function gravatar_url(User $user, array $options = ["size" => 80])
{
$gravatar_id = md5(strtolower($user->email));
return $gravatar_url = "https://secure.gravatar.com/avatar/{$gravatar_id}?s={$options["size"]}";
}
}
7.2 ユーザー登録フォーム
7.2.1 form_forを使用する
/resources/views/users/create.blade.php
@extends('layouts.application')
@section('title', 'Sign up')
@section('content')
<h1>Sign up</h1>
<div class="row">
<div class="col-md-6 offset-md-3">
{{ Form::model($user, ['url' => ['users']]) }}
<div class="mb-3">
{{ Form::label('name', 'Name', ['class' => 'form-label fw-bold']) }}
{{ Form::text('name', null, ['class' => 'form-control']) }}
</div>
<div class="mb-3">
{{ Form::label('email', 'Email', ['class' => 'form-label fw-bold']) }}
{{ Form::email('email', null, ['class' => 'form-control']) }}
</div>
<div class="mb-3">
{{ Form::label('password', 'Password', ['class' => 'form-label fw-bold']) }}
{{ Form::password('password', ['class' => 'form-control']) }}
</div>
<div class="mb-3">
{{ Form::label('password_confirmation', 'Password confirmation', ['class' => 'form-label fw-bold']) }}
{{ Form::password('password_confirmation', ['class' => 'form-control']) }}
</div>
{{ Form::submit("Create my account", ["class" => "btn btn-primary w-100"]) }}
{{ Form::close() }}
</div>
</div>
@endsection
7.2.2 フォームHTML
7.3 ユーザー登録失敗
7.3.1 正しいフォーム
コントローラにユーザーを保存するアクションを追加
/app/Http/Controllerss/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();
return redirect()->route("signup");
}
7.3.2 Strong Parameters
7.3.3 エラーメッセージ
エラーメッセージを表示するようレイアウト修正
/resources/views/users/create.blade.php
<div class="col-md-6 offset-md-3">
{{ Form::model($user, ['url' => ['users']]) }}
@include('shared.error_messages')
<div class="mb-3">
{{ Form::label('name', 'Name', ['class' => 'form-label fw-bold']) }}
{{ Form::text('name', null, ['class' => 'form-control']) }}
</div>
<div class="mb-3">
{{ Form::label('email', 'Email', ['class' => 'form-label fw-bold']) }}
{{ Form::email('email', null, ['class' => 'form-control']) }}
</div>
<div class="mb-3">
{{ Form::label('password', 'Password', ['class' => 'form-label fw-bold']) }}
{{ Form::password('password', ['class' => 'form-control']) }}
</div>
<div class="mb-3">
{{ Form::label('password_confirmation', 'Password confirmation', ['class' => 'form-label fw-bold']) }}
{{ Form::password('password_confirmation', ['class' => 'form-control']) }}
</div>
{{ Form::submit("Create my account", ["class" => "btn btn-primary w-100"]) }}
{{ Form::close() }}
</div>
/resources/views/shared/error_messages.blade.php
@if ($errors->any())
<div id="error_explanation">
<div class="alert alert-danger">
The form contains {{ $errors->count() . Illuminate\Support\Str::plural('error', $errors->count()) }}.
</div>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
7.3.4 失敗時のテスト
/tests/Feature/UsersSignupTest.php
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
class UsersSignupTest extends TestCase
{
public function testInvalidSignup()
{
$this->get("signup");
$count = User::all()->count();
$response = $this->followingRedirects()
->post("users", [
"name" => "",
"email" => "user@invalid",
"password" => "foo",
"password_confirmation" => "bar"
]);
$this->assertSame($count, User::all()->count());
$response->assertViewIs("users.create");
}
}
課題
/tests/Feature/UsersSignupTest.php
$dom = $this->dom($response->content());
$this->assertSame(1, $dom->filter('div#error_explanation')->count());
$this->assertSame(1, $dom->filter('div.alert-danger')->count());
/routes/web.php
Route::get('signup', [UsersController::class, 'create'])->name('signup');
Route::post('signup', [UsersController::class, 'store'])->name('signup');
Route::resource('users', UsersController::class)->except(["create", "store"]);
/resources/views/users/create.blade.php
{{ Form::model($user, ['route' => 'signup']) }}
/tests/Feature/UsersSignupTest.php
$response = $this->followingRedirects()
->post("signup", [
7.4 ユーザー登録成功
7.4.1 登録フォームの完成
/app/Http/Conotrollers/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();
return redirect()->route("users.show", $user);
}
7.4.2 flash
/app/Http/Coontrollers/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();
session()->flash("message", ['success' => 'Welcome to the Sample App!']);
return redirect()->route("users.show", $user);
}
/resources/views/layouts/application.blade.php
<div class="container">
@if(session('message'))
@foreach (session('message') as $message_type => $message)
<div class="alert alert-{{ $message_type }}">{{ $message }}</div>
@endforeach
@endif
@yield('content')
</div>
7.4.3 実際のユーザー登録
7.4.4 成功時のテスト
/tests/Feature/UsersSignupTest.php
public function testValidSignup()
{
$this->get(route('signup'));
$count = User::all()->count();
$response = $this->followingRedirects()
->post('/signup', [
'name' => "Example User",
'email' => "user@example.com",
'password' => "password",
'password_confirmation' => "password"
]);
$this->assertSame($count + 1, User::all()->count());
$response->assertViewIs("users.show");
}
課題
$response->assertSeeText("Welcome to the Sample App!");
7.5 プロのデプロイ
7.5.1 本番環境でのSSL
ミドルウェア追加
sail artisan make:middleware ForceHttps
/app/Http/Middleware/ForceHttps.php
class ForceHttps
{
public function handle($request, Closure $next)
{
if (!$request->secure() && config('app.env') === 'production') {
return redirect()->secure($request->getRequestUri(), 301);
}
return $next($request);
}
}
/app/Http/Kernel.php
protected $middlewareGroups = [
'web' => [
...
\App\Http\Middleware\ForceHttps::class,
],
「クラウド」ロードバランサプロバイダを使用している場合は下記のように修正
/app/Http/Middleware/TrustProxies.php
class TrustProxies extends Middleware
{
protected $proxies = '*';
}
Sanctumのマイグレーションが不要な場合は下記を追記
/app/Providers/AppServiceProvider
public function register()
{
Sanctum::ignoreMigrations();
}
The maximum column size is 767 bytes.の環境で動かす場合は下記のように修正
/config/database.php
'mysql' => [
'driver' => 'mysql',
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
7.5.2 本番環境用のWebサーバー
7.5.3 本番環境へのデプロイ
herokuにmysqlを追加してない場合は追加
7.6 最後に
参考
https://qiita.com/sutara79/items/9fd442a81001842aeba1
http://kayakuguri.github.io/blog/2017/10/27/laravel-https-loadbalancer/
https://qiita.com/Takao_/items/aeb3570b42a6aeb5461f
https://qiita.com/yukibe/items/5c1910e259ff4e6498db