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

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

詳細はこちら
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Laravel

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

PHP

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

Q&A

解決済

3回答

4837閲覧

PHP(Laravel)を使ってアプリを作っていますが、記事(blog)を更新する際にエラー(Call to a member function each() on string)がでます。

tkm-mkzk

総合スコア4

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Laravel

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

PHP

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

0グッド

0クリップ

投稿2021/03/20 07:53

編集2021/03/20 09:44

PHP(Laravel)を使ってアプリを作っていますが、記事(blog)を更新する際にエラー(Call to a member function each() on string)がでます。

PHP(Laravel)を使ってアプリを作っていますが、記事(blog)を更新する際にエラー(Call to a member function each() on string)がでます。vue.jsを使ってタグ機能を実装しているときにこのエラーが発生しました。それ以前は正常に更新できていました。

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

Error Call to a member function each() on string

該当のソースコード

BlogController.php

php

1<?php 2 3namespace App\Http\Controllers; 4 5use Illuminate\Http\Request; 6use App\Models\Blog; 7use App\Models\Tag; 8use App\Http\Requests\StoreBlog; 9 10 11class BlogController extends Controller 12{ 1314 15 /** 16 * Show the form for creating a new resource. 17 * 18 * @return \Illuminate\Http\Response 19 */ 20 public function create() 21 { 22 return view('blog.create'); 23 } 24 25 /** 26 * Store a newly created resource in storage. 27 * 28 * @param \Illuminate\Http\Request $request 29 * @return \Illuminate\Http\Response 30 */ 31 public function store(StoreBlog $request) 32 { 33 $blog = new Blog; 34 35 $blog->fill($request->all()); 36 $blog->user_id = $request->user()->id; 37 38 $blog->save(); 39 40 $request->tags->each(function ($tagName) use ($blog) { 41 $tag = Tag::firstOrCreate(['name' => $tagName]); 42 $blog->tags()->attach($tag); 43 }); 44 45 return redirect('blog/index'); 46 } 47 48 /** 49 * Show the form for editing the specified resource. 50 * 51 * @param int $id 52 * @return \Illuminate\Http\Response 53 */ 54 public function edit($id) 55 { 56 $blog = Blog::find($id); 57 58 $tagNames = $blog->tags->map(function ($tag) { 59 return ['text' => $tag->name]; 60 }); 61 62 return view('blog.edit', [ 63 'blog' => $blog, 64 'tagNames' => $tagNames, 65 ]); 66 } 67 68 /** 69 * Update the specified resource in storage. 70 * 71 * @param \Illuminate\Http\Request $request 72 * @param int $id 73 * @return \Illuminate\Http\Response 74 */ 75 public function update(Request $request, $id) 76 { 77 $blog = Blog::find($id); 78 79 $blog->title = $request->input('title'); 80 $blog->content = $request->input('content'); 81 $blog->user_id = $request->user()->id; 82 83 $blog->save(); 84 85 $blog->tags()->detach(); 86 $request->tags->each(function ($tagName) use ($blog) { 87 $tag = Tag::firstOrCreate(['name' => $tagName]); 88 $blog->tags()->attach($tag); 89 }); 90 91 return redirect('blog/index'); 92 } 93 9495}

resources/js/components/BlogTagsInput.vue

vue

1<template> 2 <div> 3 <input 4 type="hidden" 5 name="tags" 6 :value="tagsJson" 7 > 8 <vue-tags-input 9 v-model="tag" 10 :tags="tags" 11 placeholder="タグを5個まで入力できます" 12 :autocomplete-items="filteredItems" 13 @tags-changed="newTags => tags = newTags" 14 /> 15 </div> 16</template> 17 18<script> 19import VueTagsInput from '@johmun/vue-tags-input'; 20 21export default { 22 components: { 23 VueTagsInput, 24 }, 25 props: { 26 initialTags: { 27 type: Array, 28 default: [], 29 }, 30 }, 31 32 data() { 33 return { 34 tag: '', 35 tags: this.initialTags, 36 autocompleteItems: [{ 37 text: 'Spain', 38 }, { 39 text: 'France', 40 }, { 41 text: 'USA', 42 }, { 43 text: 'Germany', 44 }, { 45 text: 'China', 46 }], 47 }; 48 }, 49 computed: { 50 filteredItems() { 51 return this.autocompleteItems.filter(i => { 52 return i.text.toLowerCase().indexOf(this.tag.toLowerCase()) !== -1; 53 }); 54 }, 55 tagsJson() { 56 return JSON.stringify(this.tags) 57 }, 58 }, 59}; 60</script> 61<style lang="css" scoped> 62 .vue-tags-input { 63 max-width: inherit; 64 } 65</style> 66<style lang="css"> 67 .vue-tags-input .ti-tag { 68 background: transparent; 69 border: 1px solid #747373; 70 color: #747373; 71 margin-right: 4px; 72 border-radius: 0px; 73 font-size: 13px; 74 } 75</style>

resources/views/blog/edit.blade.php

php

1@extends('layouts.app') 2 3@section('content') 4<div class="container"> 5 <div class="row justify-content-center"> 6 <div class="col-md-8 header-margin footer-bottom"> 7 <div class="card"> 8 <div class="card-header">{{ __('編集') }}</div> 9 <div class="card-body"> 10 @if (session('status')) 11 <div class="alert alert-success" role="alert"> 12 {{ session('status') }} 13 </div> 14 @endif 15 @if ($errors->any()) 16 <div class="alert alert-danger"> 17 <ul> 18 @foreach ($errors->all() as $error) 19 <li>{{ $error }}</li> 20 @endforeach 21 </ul> 22 </div> 23 @endif 24 <form method="POST" action="{{ route('blog.update', ['id' => $blog->id ]) }}"> 25 @include('blog.form') 26 <button type="submit" class="btn blue-gradient btn-block">更新する</button> 27 </form> 28 </div> 29 </div> 30 </div> 31 </div> 32</div> 33@endsection

resources/views/blog/form.blade.php

php

1@csrf 2<div class="md-form"> 3 <label>タイトル</label><br> 4 <input type="text" name="title" class="form-control" required value="{{ $blog->title ?? old('title') }}"> 5</div> 6 7<div class="form-group"> 8 <blog-tags-input 9 :initial-tags='@json($tagNames ?? [])' 10 > 11 </blog-tags-input> 12</div> 13<div class="form-group"> 14 <label></label> 15 <textarea name="content" required class="form-control" rows="16" placeholder="本文">{{ $blog->content ?? old('content') }}</textarea> 16</div>

app/Http/Requests/StoreBlog.php

<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class StoreBlog 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 [ 'title' => 'required|string|max:50', // 'target_site' => 'required', 'content' => 'required|string|max:500', 'tags' => 'json|regex:/^(?!.*\s).+$/u|regex:/^(?!.*/).*$/u', ]; } public function attributes() { return [ 'title' => 'タイトル', // 'target_site' => '鍛えた部位', 'content' => '本文', 'tags' => 'タグ', ]; } public function passedValidation() { $this->tags = collect(json_decode($this->tags)) ->slice(0, 5) ->map(function ($requestTag) { return $requestTag->text; }); } }

試したこと

スペルミスを探したこと。
BlogControllerのupdateの記述を変更してみたこと。

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

php 7.4.14
Laravel Framework 8.28.1
vue 2.6.11

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

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

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

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

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

guest

回答3

0

ベストアンサー

Call to a member function each() on string
このエラーはPHPのエラーなのでVue.jsはあまり関係ありません
意味は文字列にeachというメソッドはありませんです。

$request->tags

このtagsが文字列で渡ってきているのではないでしょうか?

投稿2021/03/20 08:08

編集2021/03/20 08:08
mikkame

総合スコア5036

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

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

tkm-mkzk

2021/03/20 09:47 編集

回答ありがとうございます。 storeメソッドもほとんど同じ記述で保存ができているのですが、なぜupdateメソッドはできないのでしょうか? また、知識不足で申し訳ないのですが、具体的にはどのような記述にしたら、動きますでしょうか? 宜しくお願い致します。 追加で記載したのですが、 ``` public function passedValidation() { $this->tags = collect(json_decode($this->tags)) ->slice(0, 5) ->map(function ($requestTag) { return $requestTag->text; }); } ``` 上記のメソッドにより変換はしています。
mikkame

2021/03/20 10:06

updateの引数の型を確認して見てください
tkm-mkzk

2021/03/20 11:58

updateの記述を public function update(StoreBlog $request, Blog $blog) { $blog->fill($request->all()); $blog->user_id = $request->user()->id; $blog->save(); $blog->tags()->detach(); $request->tags->each(function ($tagName) use ($blog) { $tag = Tag::firstOrCreate(['name' => $tagName]); $blog->tags()->attach($tag); }); return redirect('blog/index'); } に変えてみたところ上手く動きました。 ありがとうございました。また宜しくお願い致します。
guest

0

何行目でこのエラーが出るか、特定は出来てますか?
これは配列であるべきところが文字列になっているというエラーなので、何行目の文でそのエラーになるか、特定してみてください。

投稿2021/03/20 10:00

編集2021/03/20 10:03
riyo

総合スコア33

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

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

tkm-mkzk

2021/03/20 12:01

回答ありがとうございます。 無事解決しました。 また宜しくお願い致します。
guest

0

htmlのformの中にVueで別のinput(blog-tags-input)を書いても
htmlとVueは全く繋がってないので
html側から送信してもvueのtagsは送信されない。

Vueでフォームを作るなら送信まで含めて全部Vueで作る。
Vueからの送信はaxiosを使う、って所まで書いておかないとjQueryを持ち出してくる人がいる。

投稿2021/03/20 09:14

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

mikkame

2021/03/20 10:07

よく読みましょう。 formにhiddenでjson化されたtagsを埋め込んでいます
tkm-mkzk

2021/03/20 11:59

回答ありがとうございます。 無事解決しました。また宜しくお願い致します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問