0
0

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 チュートリアル【7章】フォーム

Last updated at Posted at 2020-11-14

環境

  • 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

0
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?