前回のTurbolinks、再びにおいて掲載した記事に、修正が必要なことに気づきました。登録フォームのPOSTでバリデーションエラーが出て同画面に戻るときは問題ないのですが、エラーがなく登録完了してホーム画面へリダイレクトされたときが問題です。
以下のように、画面はホーム画面の中身となっていますが、ブラウザのURLがhomeであるべきところ、registerのままでした。

これを修正するには、まずブレードのインラインのjsから、
...
@section('script')
$(document).on('turbolinks:load', function() {
$("form").on("submit", function(event) {
event.preventDefault();
$.ajax({
url: '/register',
type: 'POST',
dataType: 'html',
processData: false,
contentType: false,
cache: false,
data: new FormData($("form")[0])
}).done(function(response, status, $xhr) {
var redirect = $xhr.getResponseHeader('Turbolinks-Location');
if (redirect) { // 投稿成功でリダイレクトしたとき
Turbolinks.visit(redirect);
} else { // バリデーションエラーのとき
var referrer = window.location.href;
Turbolinks.controller.cache.put(referrer, Turbolinks.Snapshot.wrap(response));
Turbolinks.visit(referrer, { action: 'restore' });
}
});
});
});
@endsection
変更は、投稿で成功したときを認識して、Turbolinks.visit()をリダイレクト先でコールするところです。
さて、問題は投稿が成功したか否かをどう判定するか、です。
それには、サーバーサイドでPOSTが生成するレスポンスのヘッダーにリダイレクト先を含む項目を追加してクライアント(ブラウザ)にコミュニケートする必要があります。上の例では、ヘッダーにTurbolinks-Locationの項目に値があれば、リダイレクトが必要という条件文になりました。その情報がなければ、バリデーションエラーが発生したので同じ画面を表示します。
さて、POSTのレスポンスにこの特別なヘッダーの情報を追加するには、以下のようにコントローラを編集します。
namespace App\Http\Controllers\Auth;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
// register()で使用される以下の2行の宣言が必要!
use Illuminate\Http\Request;
use Illuminate\Auth\Events\Registered;
class RegisterController extends Controller
{
use RegistersUsers;
...
/**
* Handle a registration request for the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function register(Request $request)
{
$this->validator($request->all())->validate();
event(new Registered($user = $this->create($request->all())));
$this->guard()->login($user);
// オリジナルのコード
// return $this->registered($request, $user)
// ?: redirect($this->redirectPath());
return response('success', 200)
->header('Turbolinks-Location', $this->redirectPath());
}
}
RegistersUsersのトレイトで定義されている、register()メソッドをコピーペーストして上書きします。
ヘッダーのTurbolinks-Locationには、リダイレクト先のURLが含まれることになります。
ちなみに、response()で指定している、’success’の文字列は使用しないのでなんでもよいです。空でも。
これで登録を実行すると、POSTのヘッダーには以下のように, Turbolinks-Locationは/homeの値となります。そして、その値が先のインラインのjsで抽出されて、Turbolinks.visit()に渡されてbodyタグの中身を取り換えてブラウザのURLを変更します。
HTTP/1.1 200 OK Date: Fri, 13 Dec 2019 17:31:21 GMT Server: Apache/2.4.38 (Fedora) OpenSSL/1.1.1b X-Powered-By: PHP/7.2.16 Cache-Control: no-cache, private Turbolinks-Location: /home ...
リダイレクト先には、Turbolinks-Locationというヘッダーの変数名を使用しましたが、他と重複がなければどんな名前でもよいです。サーバーとクラインとで一致している限り。
コントローラを編集しなければならない部分が残念ですが、たいした編集ではないので、私の中ではやはりサイトのSPA化ではまだまだコストパフォーマンスが大きい技術です。
メルマガ購読の申し込みはこちらから。