質問をすることでしか得られない、回答やアドバイスがある。

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

ただいまの
回答率

88.20%

laravelのCRUDで画像をアップロードする方法

受付中

回答 1

投稿

  • 評価
  • クリップ 2
  • VIEW 1,003

SENNA0510

score 10

LaravelでCRUDの勉強をしています。
以下に詳細を記載しますので、原因や対策など教えて頂けると助かります。。。

■投稿の流れ
入力フォーム → 確認画面 → 完了画面

■エラーになる部分
確認画面までは画像のパスが取得できていますが
そこから登録ボタンをクリックするとエラー画面になります。(完了画面に遷移しない)

■エラー内容
Symfony \ Component \ HttpKernel \ Exception \ MethodNotAllowedHttpException
No message
上記のような文が出てくるので何が原因なのかもわからない状態です。

■試したこと
・入力フォーム、確認画面ともに「enctype="multipart/form-data"」を指定
・「php aritsan storage:link」コマンド実行

■コードは以下
create.blade.php

@extends('layouts.app')

@section('content')
<div class="clientWrap">
<h3>Add</h3>
<p>
  <span class="label label-danger">入力画面</span> -> 確認画面 -> 完了画面
</p>

<form class="" onkeypress=""action="{{ url('/client/confirm') }}" method="post" enctype="multipart/form-data">
  {{ csrf_field() }}
  <p>
    <input type="text" name="name" placeholder="名前" value="{{ old('name') }}">
    @if ($errors->has('name'))
    <span class="error">{{ $errors->first('name') }}</span>
    @endif
  </p>
  <p>
    <input type="text" name="age" placeholder="年齢" value="{{ old('age') }}">
    @if ($errors->has('age'))
    <span class="error">{{ $errors->first('age') }}</span>
    @endif
  </p>
  <p>
    <input type="text" name="email" placeholder="アドレス" value="{{ old('email') }}">
    @if ($errors->has('email'))
    <span class="error">{{ $errors->first('email') }}</span>
    @endif
  </p>
  <p><textarea name="memo" rows="8" cols="80" placeholder="備考">{{ old('memo') }}</textarea></p>

  <p>
    <label class="col-sm-3 control-label" for="image">画像アップロード</label>
    <input type="file" name="photo" class="form-control{{ $errors->has('image') ? ' is-invalid' : '' }}" placeholder="ファイル">
    @if ($errors->has('image'))
    <span class="invalid-feedback">
    <strong>{{ $errors->first('image') }}</strong>
    </span>
    @endif
  </p>



  <input type="submit" name="" value="確認">

</form>
</div>
@endsection

confirm.blade.php

@extends('layouts.app')


@section('content')
<div class="clientWrap">
  <h3>confirm</h3>
  <p>
    入力画面 -> <span class="label label-danger">確認画面</span> -> 完了画面
  </p>

  <form class="" onkeypress=""action="{{ url('/client/finish') }}" method="post" enctype="multipart/form-data">

    <input type="hidden" name="_token" value="{{ csrf_token() }}">
    <input type="hidden" name="name" value="{{ $name }}">
    <input type="hidden" name="email" value="{{ $email }}">
    <input type="hidden" name="age" value="{{ $age }}">
    <input type="hidden" name="memo" value="{{ $memo }}">
    <input type="hidden" name="photo" value="{{ $photo }}">

    <p>名前:{{$name}}</p>
    <p>年齢:{{$age}}</p>
    <p>メールアドレス:{{$email}}</p>
    <p>備考:{!! nl2br(e($memo)) !!}</p>
    <p>画像のパス:{{ $photo }}</p>


    <input type="submit" name="action" value="戻る">
    <input type="submit" name="action" value="登録">

  </form>
</div>
@endsection

ClientsController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Client;
use App\Http\Requests\ClientRequest;

class ClientsController extends Controller
{

    public function __construct() {
      $this->middleware('auth');
    }

    //
    public function index() {
      $clients = Client::latest()->get();//Clientモデルにあるデータを登録の新しい順に取得してくる
      return view('client.list')->with('clients', $clients);
    }

    public function show(Client $client) {
      return view('client.show')->with('client', $client);
    }

    public function create() {
      return view('client.create');
    }

    public function confirm(ClientRequest $request) {
      $data = $request->all();

      return view('client.confirm')->with($data);
    }

    public function store(ClientRequest $request) {
      $action = $request->get('action');// name=action の value名を取得
      $input = $request->except('action');// 入力内容を取得

      if($action === '登録') {
        $path = "app/".$request->file('image')->store('public/images');
        $client = new Client();
        $client->clientName = $request->name;
        $client->clientAge = $request->age;
        $client->clientEmail = $request->email;
        $client->clientMemo = $request->memo;
        $client->clientImagePath = basename($path);
        $client->save();

        return view('client.finish');
      } else {
        return redirect('/client/create')->withInput($input);
      }

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

MethodNotAllowedHttpException


は、route設定に記述されていないmethodで、URLにアクセスした際に発生するエラーですね。

で、

■エラーになる部分
確認画面までは画像のパスが取得できていますが
そこから登録ボタンをクリックするとエラー画面になります。(完了画面に遷移しない) 

とのことなので、恐らく

完了画面にPOSTし、バリデーションエラーが発生。
それにより、1つ前の画面confirmにで戻ってくるが、postしか許可されていないので、MethodNotAllowedHttpExceptionが発生。。。

という状態ではないかと推測します。

上記を踏まえて、気になるところと言えば、使っているFormRequestが同じだということでしょうか。

特に画像の項目ですが、

入力画面から送信される<input type="file" name="photo">
※photoは文字列です。tmpに一時ファイルが存在します。

と、

確認画面から送信される<input type="hidden" name="photo" value="{{ $photo }}">
※photoは文字列です。tmpに一時ファイルはありません。

の差を、ClientRequestの中できちんと処理分けされていますか?


コメント受けての追記です。

フレームワークを使わずに、ファイルのアップロード処理を作成されたことはありますか?
もしなければ、まずはそちらから作ってみることをお勧めします。
ここはphpを使う上で基本的なことなので、フレームワークをつかう前に理解しておくべき部分だと思います。

これが出来るようになれば、<input type="file" name="photo">と、<input type="hidden" name="photo">の差が分かるはずです。
そして、この差が分かれば、今回のエラーについても原因が見えてくるはず。。。

確認画面から送信される<input type="hidden" name="photo">は、
FormRequestのルールに記載されている

'photo' => 'required|file|image|mimes:jpeg,png,jpg,gif|max:2048'


この、file|image|mimes:jpeg,png,jpg,gifのチェックを突破できないので、バリデーションエラーが発生しています。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/03/07 16:44

    ご回答ありがとうございました。
    送って頂いた助言を読みClientRequesの中身を見てみましたが
    処理分けして出来てないと思います。

    以下がコードです。
    普通のバリデーション設定しか記述してないです。

    入力画面から送信される<input type="file" name="photo">と
    確認画面から送信される<input type="hidden" name="photo" value="{{ $photo }}">の
    処理分けという点が理解できないのですが
    具体的にはどのようにしたらよいのでしょうか。

    お手数ですが、、、教えて頂けると幸いです。

    ```php
    <?php

    namespace App\Http\Requests;

    use Illuminate\Foundation\Http\FormRequest;

    class ClientRequest extends FormRequest
    {
    /**
    * Determine if the user is authorized to make this request.
    *
    * @return bool
    */
    public function authorize()
    {
    return true;
    }

    /**
    * Get the validation rules that apply to the request.
    *
    * @return array
    */
    public function rules() {
    return [
    //
    'name' => 'required|min:2',
    'age' => 'required|numeric',
    'email' => 'required|email',
    'photo' => 'required|file|image|mimes:jpeg,png,jpg,gif|max:2048'
    ];
    }
    public function messages() {
    return [
    'required' => '必須です',
    'min' => '2文字以上です',
    'numeric' => '数字で入力してください',
    'email' => 'メールアドレス形式で入力してください',
    'photo' => '対応している形式でアップしてください'
    ];
    }
    }

    ```

    キャンセル

  • 2019/03/08 11:25

    追記してみたので、ご確認ください。

    キャンセル

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

  • ただいまの回答率 88.20%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る