LoginSignup
0
0

More than 3 years have passed since last update.

Laravel で Ruby on Rails チュートリアル【12章】

Posted at

環境

  • Laravel 5.5
  • PHP 7.2

この章でやること

12.1 PasswordResetsリソース

12.1.1 PasswordResetsコントローラー

ルート追加(/routes/web.php)
php
Route::get('password_resets/create', "PasswordResetsController@create")->name("resets.create");
Route::post('password_resets', "PasswordResetsController@store")->name("resets.store");
Route::get('password_resets/{token}/edit', "PasswordResetsController@edit")->name("resets.edit");
Route::patch('password_resets/{token}', "PasswordResetsController@update")->name("resets.update");

レイアウト(/resources/views/sessions/create.blade.php)
ppp
{{ Html::linkRoute("resets.create", "(forgot password)") }}

12.1.2 新しいパスワードの設定

ミグレーション(/dataase/migrations/[timestamp]_add_reset_to_users.php)
```php
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('reset_digest')->nullable();
$table->dateTime('reset_sent_at')->nullable();
});
}

public function down()
{
    Schema::table('users', function (Blueprint $table) {
        $table->dropColumn('reset_digest');
        $table->dropColumn('reset_sent_at');
    });
}
(/resources/views/password_resets/create.blade.php)
```html
@extends('layouts.application')

@section('title', 'Forgot password')

@section('content')
<h1>Forgot password</h1>

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

        {{ Form::label('email') }}
        {{ Form::text('email', "", ["class" => "form-control"]) }}

        {{ Form::submit("Submit", ["class" => "btn btn-primary"]) }}
        {{ Form::close() }}
    </div>
</div>
@endsection

(/app/Http/Controllers/PasswordResetsController.php)
php
public function create()
{
return view("password_resets.create");
}

12.1.3 createアクションでパスワード再設定

(/app/Http/Conttollers/PasswordResetsController.php)
php
public function store(Request $request)
{
$user = User::where("email", $request->email)->first();
if (!$user) {
session()->flash('message', ['danger' => 'Email address not found']);
return redirect()->back();
}
$reset_token = str_random(22);
$user->reset_digest = bcrypt($reset_token);
$user->reset_sent_at = Carbon::now();
$user->save();
$user->sendPasswordResetMail($reset_token);
session()->flash('message', ['info' => 'Email sent with password reset instructions']);
return redirect("/");
}

(/app/User.php)
php
public function sendPasswordResetMail($token)
{
Mail::to($this)->send(new PasswordReset($this, $token));
}

12.2 パスワード再設定のメール送信

12.2.1 パスワード再設定のメールとテンプレート

(/app/Mail/PasswordReset.php)
```php
class PasswordReset extends Mailable
{
use Queueable, SerializesModels;

public $user;
public $reset_token;

public function __construct($user, $reset_token)
{
    $this->user = $user;
    $this->reset_token = $reset_token;
}

public function build()
{
    return $this->from("noreply@example.com")
                ->subject("Password reset")
                ->view('emails.password_reset');
}

}

(/resources/views/emails/password_reset.blade.php)
html

Password reset

To reset your password click the link below:

{{ Html::linkRoute("resets.edit", "Reset password", ["token" => $reset_token, "email" => $user->email]) }}

This link will expire in two hours.

If you did not request your password to be reset, please ignore this email and your password will stay as it is.


# 12.2.2 送信メールのテスト

(/tests/Unit/MailerTest.php)
```php
    public function testPasswordReset()
    {
        Mail::fake();

        $user = User::find(1);
        $reset_token = str_random(22);
        Mail::to($user)->send(new PasswordReset($user, $reset_token));
        Mail::assertSent(PasswordReset::class, function ($mail) use ($user, $reset_token) {
            $mail->build();
            $this->assertEquals("Password reset", $mail->subject);
            $this->assertTrue($mail->hasTo($user->email));
            $this->assertTrue($mail->hasFrom("noreply@example.com"));
            $this->assertEquals($user->name, $mail->user->name);
            $this->assertEquals($reset_token, $mail->reset_token);
            $this->assertEquals($user->email, $mail->user->email);
            return true;
        });
    }

12.3 パスワードを再設定する

12.3.1 editアクションで再設定

(/resources/views/password_resets/edit.blade.php)
```html
@extends('layouts.application')

@section('title', 'Reset password')

@section('content')

Reset password

{{ Form::model($user, ["route" => ["resets.update", $token], "method" => "patch"]) }} @include('shared.error_messages') {{ Form::hidden('email', $user->email) }} {{ Form::label('password') }} {{ Form::password('password', ["class" => "form-control"]) }} {{ Form::label('password_confirmation') }} {{ Form::password('password_confirmation', ["class" => "form-control"]) }} {{ Form::submit("Update password", ["class" => "btn btn-primary"]) }} {{ Form::close() }}

@endsection

(/app/Http/Controllers/PasswordResetController.php)
php
public function __construct()
{
$this->middleware(function ($request, $next) {
$user = User::where("email", $request->email)->first();
if (!$user || !$user->activated || !Hash::check($request->token, $user->reset_digest)) {
return redirect('/');
}
return $next($request);
})->only(["edit", "update"]);
}
...
public function edit(Request $request)
{
$user = User::where("email", $request->email)->first();
return view("password_resets.edit")->with(["user" => $user, "token" => $request->token]);
}
```

12.3.2 パスワードを更新する

(/app/Http/Controllers/PasswordResetsController.php)
```php
public function __construct()
{
$this->middleware(function ($request, $next) {
$user = User::where("email", $request->email)->first();
if ($user->checkExpiration()) {
session()->flash('message', ['danger' => 'Password reset has expired']);
return redirect()->back();
}
return $next($request);
})->only(["edit", "update"]);
}

public function update(Request $request)
{
    $request->validate([
        'password' => 'required|min:6|confirmed',
        'password_confirmation' => 'required|min:6',
    ]);

    $user = User::where("email", $request->email)->first();
    $user->password = bcrypt($request->password);
    $user->reset_digest = null;
    $user->save();
    Auth::login($user);
    session()->flash('message', ['success' => 'Password has been reset.']);
    return redirect()->route("users.show", $user->id);
}
(/app/User.php)
```php
    public function checkExpiration()
    {
        return $this->reset_sent_at < Carbon::now()->subHours(2);
    }

12.3.3 パスワードの再設定をテストする

(/tests/Feature/PasswordResetsTest)
```php
class PasswordResetsTest extends TestCase
{
private $user;

protected function setUp()
{
    parent::setUp();
    Artisan::call('migrate:fresh');
    $this->seed('TestSeeder');
    $this->user = User::find(1);
}

public function testPasswordResets()
{
    Mail::fake();

    $response = $this->get(route("resets.create"));
    $response->assertViewIs("password_resets.create");
    $response = $this->post(route("resets.store"), ["email" => ""]);
    $response->assertSessionHas("message");
    $response->assertRedirect(route("resets.create"));
    $response = $this->post(route("resets.store"), ["email" => $this->user->email]);
    $this->assertNotEquals($this->user->reset_digest, User::find(1)->reset_digest);
    Mail::assertSent(PasswordReset::class, 1);
    $response->assertSessionHas("message");
    $response->assertRedirect("/");

    $reset_token = str_random(22);
    $this->user->update(["reset_digest" => bcrypt($reset_token)]);
    $response = $this->get(route("resets.edit", ["token" => $reset_token, "email" => ""]));
    $response->assertRedirect("/");
    $this->user->update(["activated" => false]);
    $response = $this->get(route("resets.edit", ["token" => $reset_token, "email" => $this->user->email]));
    $response->assertRedirect("/");
    $this->user->update(["activated" => true]);
    $response = $this->get(route("resets.edit", ["token" => "wrong token", "email" => $this->user->email]));
    $response->assertRedirect("/");
    $response = $this->followingRedirects()
                    ->get(route("resets.edit", ["token" => $reset_token, "email" => $this->user->email]));
    $response->assertViewIs("password_resets.edit");
    $dom = $this->dom($response->content());
    $this->assertSame(1, $dom->filter("input[name=email][type=hidden][value=\"{$this->user->email}\"]")->count());
    $response = $this->followingRedirects()
                    ->patch(route("resets.update", $reset_token), [
                        "email" => $this->user->email,
                        "password" => "foobaz",
                        "password_confirmation" => "barquux"
                    ]);
    $this->assertSame(1, $this->dom($response->content())->filter("div#error_explanation")->count());
    $response = $this->followingRedirects()
                    ->patch(route("resets.update", $reset_token), [
                        "email" => $this->user->email,
                        "password" => "",
                        "password_confirmation" => ""
                    ]);
    $this->assertSame(1, $this->dom($response->content())->filter("div#error_explanation")->count());
    $response = $this->followingRedirects()
                    ->patch(route("resets.update", $reset_token), [
                        "email" => $this->user->email,
                        "password" => "foobaz",
                        "password_confirmation" => "foobaz"
                    ]);
    $this->assertTrue(Auth::check());
    $response->assertSeeText("Password has been reset.");
    $response->assertViewIs("users.show");
}

}
```

12.4 本番環境でのメール送信(再掲)

12.5 最後に

12.6 照明期限切れの比較

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