1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

チェックボックスの値の取得を通して、FormRequestの仕様を認識した話

Last updated at Posted at 2025-06-20

Undefined array key "tag_ids"

このエラーが出たとき、
記事の投稿時に、チェックボックスでタグを選択できるような機能を実装していました。
以下はコントローラとビューの実装です。

app\Http\Controllers\ArticleController.php
    public function store(ArticleStoreRequest $request) {

        $validated = $request->validated();
        /** @var User $user */
        $user = Auth::user();
        $article = $user->articles()->create($validated);
        
        $tag_ids = array_filter($validated['tag_ids']); //この行でエラー
        $article->tags()->attach($tag_ids);

        return to_route('articles.index');
    }
resources/views/articles/create.blade.php
<form method="POST" action="{{ route('articles.store') }}">
  @csrf
  <fieldset class="fieldset bg-base-200 border-base-300 rounded-box w-l border p-4">
    <legend class="fieldset-legend">記事投稿</legend>

    <label for="title" class="label">{{ __('Title') }}</label>
    <input type="text" class="input w-lg" placeholder="タイトル" name="title" value="{{ old('title') }}">

    <label for="content" class="label">{{ __('Content') }}</label>
    <textarea name="content" id="content" class="textarea w-lg size-100">{{ old('content') }}</textarea>

    <label for="tag_div">タグ</label>
    <div id="tag_div">
      @foreach ($tags as $tag)
        <input
          type="checkbox"
          aria-label="{{ $tag->name }}"
          class="btn btn-xs mr-2 mb-2"
          value="{{ $tag->id }}"
          id="tag_{{ $tag->id }}"
          name="tag_ids[]"
          {{ is_array(old('tag_ids')) && in_array($tag->id, old("tag_ids")) ? 'checked' : '' }}
        />
      @endforeach
    </div>

    <button type="submit" class="btn btn-neutral">{{ __('Submit') }}</button>

  </fieldset>
</form>

問題の所在はFormRequestクラスにあった!

$tag_idsというタグの配列は、ちゃんとフロントから渡しているはずなのに…」と思っていたのですが、AIに相談したところ、どうやら問題はFormRequestクラスでのバリデーションの書き方にあったようです。

FormRequestの基本を知りたい方はこちらをどうぞ

今回は、以下で説明する、FormRequestの二つの仕様を理解していなかったために、問題が起こっていたようです。

①コントローラの$request->validated()には、rulesに定義したプロパティしか渡ってこない

そのときの私は、以下のように、各要素へのバリデーションしかしていませんでした。

app\Http\Requests\ArticleStoreRequest.php
    public function rules(): array
    {
        return [
            'tag_ids.*' => ['nullable', 'numeric', Rule::exists('tags', 'id')],
        ];
    }

FormRequestクラスでバリデーションを行う場合、コントローラでは$request->validated()という形で、バリデーション済みの値を配列で取得して使います。
その配列の中には、rules()内に定義したプロパティだけが含まれます。
つまり、私はtag_idsという配列自体をrulesの中に記載していなかったので、コントローラで$request->validated()したときに、その配列の中にtag_idsが含まれていなかったのです。

対策

配列にバリデーションを実施する際は、

  • 配列自体へのバリデーション
  • 配列の各要素へのバリデーション

これらを合わせて書くようにしましょう。

よって、このように修正しました。

app\Http\Requests\ArticleStoreRequest.php
    public function rules(): array
    {
        return [
            'tag_ids'   => ['nullable', 'array'],
            'tag_ids.*' => ['numeric', Rule::exists('tags', 'id')],
        ];
    }

以上が、今回の一番大きな問題でした。
しかしもうひとつポイントがあります。

nullなプロパティは$request->validated()に含まれない

今回のチェックボックスは、一つも選択されていなくてもOKとしています。
よってrulesでも、tag_idsにはnullableを設定しました。

このように配列自体をnullableにしている場合には、少し注意が必要です。

FormRequestでは、バリデーション時にnullだったプロパティについては、コントローラまで届かない仕様になっています。$request->validated()で取得できる配列に、含まれなくなるということです。

チェックボックスがどれも未選択の場合、そもそもブラウザからtag_idsというnameの値は送信されてきません。つまり、FormRequestでのバリデーション時には、tag_idsnullということになります。
すると、コントローラで$request->validated()['tag_ids']としても、何も取得することができません。
Undefined array key "tag_ids"というエラーが起こってしまいます。

対策

prepareForValidationという、バリデーションの前にデータを加工するメソッドを使いましょう。
データの正規化や加工に便利なメソッドです。
今回はこの中で、nullの場合に空の配列を入れるようにしておきます。

app\Http\Requests\ArticleStoreRequest.php
    public function rules(): array
    {
        return [
            'tag_ids'   => ['nullable', 'array'],
            'tag_ids.*' => ['numeric', Rule::exists('tags', 'id')],
        ];
    }

    protected function prepareForValidation()
    {
        $this->merge([
            'tag_ids' => $this->input('tag_ids', []),
        ]);
    }

inputメソッドでは、第二引数にデフォルト値を設定できますので、ここに空の配列を入れます。
$this->mergeは、引数に渡した内容を、リクエストデータに反映するためのメソッドです。
これで、tag_idsnullの場合には空の配列をtag_idsに代入してから、バリデーションへ進むことができます。
すると、空の配列がコントローラへ渡るため、Undefined array key "tag_idsというエラーは起こらなくなります。

今回は以上2点を押さえることで、FormRequestクラスを適切な形にできました。

参考サイト

1
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?