@wadigchan

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

ajaxの422エラー

解決したいこと

現在、laravelを使ったブログを作っています。
TOAST UI Editorというマークダウンエディタを使っているのですが、ここに書いたブログ内容をjs経由でコントローラに送ることができません。

発生している問題・エラー

エラー内容はこんな感じです。

jqXHR          : 422
textStatus     : error
errorThrown    : undefined

422エラーは、中に含まれている指示が処理できなかったことを表しているらしいのですが、どの指示がどう間違っているのかわかりません。
jsファイルのコードは下記のようになっています。
マークダウンエディタに書いた記事内容は、const contents = editor.getValue();で取得しています。
内容がcontentsに送られてきているのは確認済みです。

create.js
$(function($){
    $('#form').submit(function(event) {
        const contents = editor.getValue();
        $.ajax({
            url : "/posts" ,
            type : "POST",
            dataType : "json",
            data: { "content" : contents },
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr("content")
              },
        })
        .done(function() {
            alert('成功');
        })
        .fail(function(jqXHR, textStatus, errorThrown) {
            alert('ファイルの取得に失敗しました。');
            console.log("ajax通信に失敗しました");
            console.log("jqXHR          : " + jqXHR.status); // HTTPステータスが取得
            console.log("textStatus     : " + textStatus);    // タイムアウト、パースエラー
            console.log("errorThrown    : " + errorThrown.message); // 例外情報
         });
    });
});

ブログをPOSTするコントローラはこちらです。

PostController
public function store(PostRequest $request)
    {
        dd($request->all());

        $post = new Post;

        $post->user_id = $request->user_id;
        $post->content = $request->content;
        $post->title = $request->title;
        $post->is_published = $request->is_published;

        ...以下省略

    }

まずは、$request->contentに、const content = editor.getValue();この内容が送られてくるようにしたいです。
ブログ作成画面はこうなっています。

create.blade.php
@extends('layouts.app')

@section('content')

<link rel="stylesheet" href="https://uicdn.toast.com/tui-editor/latest/tui-editor.css">
<link rel="stylesheet" href="https://uicdn.toast.com/tui-editor/latest/tui-editor-contents.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.4/codemirror.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css">


<div class="card-header">新規投稿</div>
<div class="card-body">
  @if (session('status'))
  <div class="alert alert-success" role="alert">
    {{ session('status') }}
  </div>
  @endif

  <div class="card">
    <div class="card-body">
      @if ($errors->any())
      <div class="alert alert-danger">
        <ul>
          @foreach ($errors->all() as $error)
          <li>{{ $error }}</li>
          @endforeach
        </ul>
      </div>
      @endif
      <form action="{{ route('posts.store') }}" method="POST" enctype="multipart/form-data" id="form">
        {{ csrf_field() }}

        <div class="form-group">
          <label for="exampleInputEmail1">タイトル</label>
          <input type="text" class="form-control" id="exampleInputEmail1" placeholder="title" name="title">
        </div>

        <div class="form-group">
          <label for="exampleInputEmail1">カテゴリ</label>
          <input type="text" class="form-control" placeholder="category" name="tagcategory">
        </div>

        <div class="form-group">
          <label for="exampleFormControlFile1">サムネイル</label>
          <input type="file" class="form-control-file" id="exampleFormControlFile1" name="image">
        </div>

        <label for="exampleInputEmail1">本文</label>
        <div id="file_viewer"></div>

        <div id="editSection"></div>

        <div class="form-group">
          <label for="exampleFormControlSelect1">公開設定</label>
          <select input type="id" id="exampleFormControlSelect1" name="is_published">
            <option value="1">公開</option>
            <option value="0">非公開</option>
          </select>
        </div>


        <input type="hidden" name="user_id" value="{{ Auth::id() }}">

        <button type="submit" class="btn btn-primary" id="button">投稿</button>
        <a href="{{ route('posts.index') }}" class="btn btn-primary">キャンセル</a>
      </form>
    </div>
  </div>
</div>


<script  type="application/javascript" src="https://uicdn.toast.com/tui-editor/latest/tui-editor-Editor-full.js"></script>
<script  type="application/javascript" src="{{ asset('js/create.js') }}"></script>

@endsection

自分でも訳が分からなくなっているので説明不足な部分があったらすみません。

0 likes

1Answer

Laravelが422を返すケースとして、バリデーションエラーがあるようです。

XHRリクエスト中にvalidateメソッドを使用すると、Laravelはリダイレクト応答を生成しません。代わりに、Laravelはすべてのバリデーションエラーを含むJSONレスポンスを生成します。このJSONレスポンスは、422 HTTPステータスコードとともに送信されます。

jqXHR.responseJSONにバリデーションエラーの情報などは含まれていないですか?

If json is specified, the response is parsed using jQuery.parseJSON before being passed, as an object, to the success handler. The parsed JSON object is made available through the responseJSON property of the jqXHR object.

また、JavaScriptからの通信はブラウザのデベロッパーツールで確認することができます。
ChromeであればデベロッパーツールのNetworkタブです。

その他、LaravelのログやWebサーバのアクセスログなどにヒントがあるかもしれません。

1Like

Comments

  1. @wadigchan

    Questioner

    いつもご回答ありがとうございます。
    ご指摘いただいたように、validationを無効にしたところ200エラーが出るようになりましたが、dataType : "text" に変えたところ成功できました。
    しかし、相変わらずコントローラにcontentが送られてこないのと、submitイベントが2回反応してしまい、成功のアラートが2回出てしまいます。
    調べたところoff()を追加で直るという記事をいくつか見ましたがやっても直りません、、
    contentが送られてこないのと、2回反応してしまうのをどうにかする方法はありますでしょうか、、?
  2. 「コントローラにcontentが送られてこない」というのは「送信できていない」「受信できていない」のどちらでしょうか?

    $.ajaxで送信しているデータを示してください。
    これはブラウザのデベロッパーツールから確認できます。

    受信しているデータも示してください。
    例えばdd($request->all())の値です。

    submitイベントが2回反応するというのは、単純にボタンを2回押しているのか、どこかからイベントを呼び出しているのだと思います。

    解決方法のひとつはフラグで状態管理するものです。
    処理中はフラグをONにし、終わったらOFFにします。
    フラグがONのときは処理中ですから、その場合は処理を行なわずに終了します。
  3. @wadigchan

    Questioner

    受信ができていません。
    ajaxの送信データは、ヘッダーが、

    リクエスト URL: http://127.0.0.1:8080/posts
    リクエスト メソッド: POST
    ステータス コード: 200 OK
    リモート アドレス: 127.0.0.1:8080
    参照ポリシー: strict-origin-when-cross-origin

    ペイロードのフォームデータにはcontentに入力した内容が書かれています。

    dd($request->all());の値は、

    array:5 [▼
    "_token" => "H15HpUhpjbfrgWGsaNAx4lv6eHM2XRUw6IL5r4HK"
    "title" => "タイトル"
    "tagcategory" => null
    "is_published" => "1"
    "user_id" => "1"
    ]

    このようになっています。
  4. もしかしてformとajaxで一度に2回送信しているのではないですか?
    だとすれば「dd($request->all())」の結果はformの方で、contentが無いのはformタグの中にinputやtextareaが無いからだと思います。

    だとすれば、どちらかに統一することになります。
    <input type="hidden" name="content">などに値を入れてformでsubmitするか、
    formを使わずにajaxで送信するか、です。
  5. @wadigchan

    Questioner

    あ、、
    絶対それが原因な気がします、、
    今回の場合、マークダウンエディタに書いた内容はjsじゃないと取得できないので、laravelのformに書いたタイトルやカテゴリをjsに送って、それをcontentと一緒にまとめてajaxでコントローラに送るということですよね?
  6. はい。
    私がコメントしたどちらかのうち「formを使わずにajaxで送信する」の方がそれです。
  7. @wadigchan

    Questioner

    ありがとうございます。
    やってみます! とても助かりました。

Your answer might help someone💌