🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

1回答

2576閲覧

Laravel8でルートモデルバインディングが上手く行きません。

rousan

総合スコア2

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2020/12/28 11:01

編集2020/12/28 11:12

前提・実現したいこと

Laravel8でTODOリストアプリを作っています。
ルートモデルバインディングでコントローラーメソッドを使用する暗黙的な結合を実装中にエラーメッセージが発生しました。

発生している問題・エラーメッセージ

まずweb.phpのルート情報1つと関連するtaskController.phpを修正し、動作確認のためログインしてみると次のエラーが出ました。

Illuminate\Routing\Exceptions\UrlGenerationException Missing required parameters for [Route: tasks.index] [URI: folders/{folder}/tasks]. (View: /Applications/MAMP/htdocs/laraveltodolist/resources/views/tasks/index.blade.php)

該当のソースコード

//web.php <?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\TaskController; use App\Http\Controllers\FolderController; use App\Http\Controllers\HomeController; Route::group(['middleware' => 'auth'], function() { Route::get('/', [HomeController::class, 'index'])->name('home'); Route::get('/folders/{folder}/tasks', [TaskController::class, 'index'])->name('tasks.index'); Route::get('/folders/create', [FolderController::class, 'showCreateForm'])->name('folders.create'); Route::post('/folders/create', [FolderController::class, 'create']); Route::get('/folders/{id}/tasks/create', [TaskController::class, 'showCreateForm'])->name('tasks.create'); Route::post('/folders/{id}/tasks/create', [TaskController::class, 'create']); Route::get('/folders/{id}/tasks/{task_id}/edit', [TaskController::class, 'showEditForm'])->name('tasks.edit'); Route::post('/folders/{id}/tasks/{task_id}/edit', [TaskController::class, 'edit']); }); Auth::routes();
//TaskController.php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Folder; use App\Models\Task; use App\Http\Requests\CreateTask; use App\Http\Requests\EditTask; use Illuminate\Support\Facades\Auth; class TaskController extends Controller { public function index(Folder $folder) { // ユーザーのフォルダを取得する $folders = Auth::user()->folders()->get(); //選ばれたフォルダに紐づくタスクを取得する $tasks = $folder->tasks()->get(); return view('tasks/index',[ 'folders' => $folders, 'current_folder_id' => $folder->id, 'tasks' => $tasks, ]); } public function showCreateForm(int $id) { return view('tasks/create',[ 'folder_id' => $id ]); } public function create(int $id,CreateTask $request) { $current_folder = Folder::find($id); $task = new Task(); $task->title = $request->title; $task->due_date = $request->due_date; $current_folder->tasks()->save($task); return redirect()->route('tasks.index',[ 'id' => $current_folder->id, ]); } public function showEditForm(int $id, int $task_id) { $task = Task::find($task_id); return view('tasks/edit',[ 'task' => $task, ]); } public function edit(int $id, int $task_id, EditTask $request) { //1 $task = Task::find($task_id); //2 $task->title = $request->title; $task->status = $request->status; $task->due_date = $request->due_date; $task->save(); //3 return redirect()->route('tasks.index',[ 'id' => $task->folder_id, ]); } }
//login.blade.php(参考) @extends('layout') @section('content') <div class="container"> <div class="row"> <div class="col col-md-offset-3 col-md-6"> <nav class="panel panel-default"> <div class="panel-heading">ログイン</div> <div class="panel-body"> @if($errors->any()) <div class="alert alert-danger"> @foreach($errors->all() as $message) <p>{{ $message }}</p> @endforeach </div> @endif <form action="{{ route('login') }}" method="POST"> @csrf <div class="form-group"> <label for="email">メールアドレス</label> <input type="text" class="form-control" id="email" name="email" value="{{ old('email') }}" /> </div> <div class="form-group"> <label for="password">パスワード</label> <input type="password" class="form-control" id="password" name="password" /> </div> <div class="text-right"> <button type="submit" class="btn btn-primary">送信</button> </div> </form> </div> </nav> <div class="text-center"> <a href="{{ route('password.request') }}">パスワードの変更はこちらから</a> </div> </div> </div> </div> @endsection
//LoginController.php(参考) <?php namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Providers\RouteServiceProvider; use Illuminate\Foundation\Auth\AuthenticatesUsers; class LoginController extends Controller { use AuthenticatesUsers; /** * Where to redirect users after login. * * @var string */ protected $redirectTo = '/'; // protected $redirectTo = RouteServiceProvider::HOME; /** * Create a new controller instance. * * @return void */ public function __construct() { $this->middleware('guest')->except('logout'); } }
//HomeController.php(参考) <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; class HomeController extends Controller { public function index() { // ログインユーザーを取得する $user = Auth::user(); // ログインユーザーに紐づくフォルダを一つ取得する $folder = $user->folders()->first(); // まだ一つもフォルダを作っていなければホームページをレスポンスする if (is_null($folder)) { return view('home'); } // フォルダがあればそのフォルダのタスク一覧にリダイレクトする return redirect()->route('tasks.index', [ 'id' => $folder->id, ]); } }

試したこと

ルートモデルバインディングでコントローラーメソッドを使用する暗黙的な結合を実装のために、まずweb.phpのルート情報を一つだけ次のようにしています。

Route::get('/folders/{folder}/tasks', [TaskController::class, 'index'])->name('tasks.index');

続きでTaskController.phpのindexアクションだけ次のようにしました。

public function index(Folder $folder) { // ユーザーのフォルダを取得する $folders = Auth::user()->folders()->get(); //選ばれたフォルダに紐づくタスクを取得する $tasks = $folder->tasks()->get(); return view('tasks/index',[ 'folders' => $folders, 'current_folder_id' => $folder->id, 'tasks' => $tasks, ]); }

ここで、動作確認のためブラウザを開き、ログインしてみると上記のエラーが出ました。

参考にしているサイトにも次のように書かれているため、何故エラーなのか分かりません。

Laravel は、ルーティング定義の URL の中括弧で囲まれたキーワード({folder})とコントローラーメソッドの仮引数名($folder)が一致していて、かつ引数が型指定(Folder)されていれば、URL の中括弧で囲まれた部分の値を ID とみなし、自動的に引数の型のモデルクラスインスタンスを作成します。

公式サイト(https://laravel.com/docs/8.x/routing#route-model-binding)(https://readouble.com/laravel/8.x/ja/routing.html)のVERSION8の説明でも同じようなことが書かれていることも確認済です。

コントローラーメソッドを使用する場合でも暗黙的な結合は可能です。繰り返しになりますが、{user}URIセグメントはApp\Models\Userタイプヒントを含むコントローラーの$user変数と一致することに注意してください。

的外れかもしれませんが、TaskController.phpのretrunの配列に'folder' => $folder->id,や'folder' => $folder,を追加してみましたが解決できませんでした。

これも的外れかもしれませんが、ログイン後にエラーがでるためHomeController.phpが関係するのかもしれないと思い、use App\Models\Folder;を追加して、indexアクションの引数を(Folder $folder)にしてみましたがダメでした。

他に何が問題なのか分からなく、お力添えいただければ幸いです。

補足情報(FW/ツールのバージョンなど)

OS Mac
PHP 7.3.11
Laravel 8.18.1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

必要なのはtasks/index.blade.php

Route::get('/folders/{folder}/tasks', [TaskController::class, 'index'])->name('tasks.index');

ルーティングでこう指定したなら使う時は↓

route('tasks.index', ['folder' => $folder->id])

tasks/index.blade.php内のroute()でたぶん'id' =>になってる。

パラメータが一つならこう書いたほうが余計なことに振り回されない。

route('tasks.index', $folder)

投稿2020/12/28 11:49

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

rousan

2020/12/28 13:22 編集

おっしゃる通りでした!tasks/index.blade.php等でもidからfolderに修正することで解決できました。一人で2日間程考えていたので大変助かりました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問