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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Laravel

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

Q&A

解決済

1回答

5114閲覧

Laravelのpublicディレクトリにstorageが表示されない

nanami0221

総合スコア18

Laravel

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

0グッド

0クリップ

投稿2021/05/25 03:16

編集2021/05/25 04:44

前提・実現したいこと

Laravelでstorageディレクトリにアップした画像をpublicディレクトリに表示させたです。
storageの保存まで問題なくできたのですが、publicにうまく表示されません。

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

表示時に404エラーが出ており、/publicディレクトリを確認したら、storageディレクトリがpublicに読み込まれていませんでした。

現状

1.○ ファイルアップ時に画像URLパスのDBの保存確認済み

2.○ 以下ディレクトリに画像アップロード確認済み
/storage/app/img/public/img/surveys/~~~~~~.png

3.× 以下ディレクトリに画像が読み込まれない
/public/storage/img/surveys/

該当のソースコード

// ディレクトリ構造 public  ∟storage   ∟img    ∟surveys     ∟読み込まれていない storage  ∟app   ∟public    ∟img     ∟surveys      ∟〜〜〜〜.png resources  ∟js   ∟components    ∟projects     ∟ProjectRegisterComponent.vue(アップロード処理が記載されているファイル)

Vue

1// 画像アップロード処理のJSファイル 2<template> 3 <div class="allWrapper"> 4 <div class="content__box"> 5 <div class="content__box__inner"> 6 <!-- 複数読み込み --> 7 <div 8 class="content__input" 9 v-for="(survey, index) in surveys" 10 :key="survey.id" 11 > 12 <div class="input__img__block"> 13 <div class="input__img__block__inner containFlexImg" 14 :class="{enter: survey.isEnter}"> 15 <img :src="survey.thumbImg" ref="thumbFile"> 16 </div> 17 <div class="input__delete" 18 :class="{get: survey.getImg}" 19 <span><img src="/assets/img/icon_batu_white.png"></span> 20 </div> 21 <label> 22 <span>{{ survey.status }}</span> 23 <input 24 type="file" 25 multiple="multiple" 26 ref="file" 27 class="avatar_name" 28 accept="image/jpeg, image/png, application/pdf" 29 /> 30 </label> 31 </div> 32 <div class="input__box" style="margin-top: 1em;"> 33 <div class="input__box subText"> 34 <textarea class="bgType" name v-model="survey.description"></textarea> 35 </div> 36 </div> 37 </div> 38 <div class="content__input"> 39 <div class="input__box"> 40 <textarea 41 class="bgType" 42 placeholder="南面が狭小の為、近隣に注意して作業してください。" 43 v-model="remark" 44 ></textarea> 45 </div> 46 <template v-if="enable_sms == '1'"> 47 <div class="content__confirmation"> 48 <label class="checkbox__label"> 49 送信する 50 <input type="checkbox" name v-model="is_send_to_project_orderer" /> 51 <div class="checkbox__block"></div> 52 </label> 53 </div> 54 </template> 55 </div> 56 </div> 57 <div class="content__submit f__center"> 58 <div class="submit__box"> 59 <a href @click.prevent="storeSurvey">現調報告する</a> 60 </div> 61 </div> 62 </div> 63</template> 64<script> 65import axios from "./../../utilities/axios"; 66import errorHandling from "./../../utilities/handling"; 67 68export default { 69 props: { 70 project_id: { 71 type: String, 72 }, 73 survey_id: { 74 type: String, 75 }, 76 enable_sms: { 77 type: String, 78 }, 79 urlPrefix: { 80 type: String 81 }, 82 }, 83 data() { 84 return { 85 surveys: [], 86 is_send_to_project_orderer: false, 87 remark: "", 88 deleted_survey_image_ids: [], 89 }; 90 }, 91 created: function () { 92 // 空データを1つ、変数へ登録 93 let emptyItem = { 94 imageId: null, 95 thumbImg: "/assets/img/noImage.png", 96 status: "画像を追加", 97 getImg: false, 98 isEnter: false, 99 file: "null", 100 description: "", 101 }; 102 this.surveys.push(emptyItem); 103 }, 104 methods: { 105 // 新規のアップロード領域を追加する 106 if (!isOverwrite) { 107 let item = { 108 imageId: null, 109 thumbImg: "/assets/img/noImage.png", 110 status: "画像を追加", 111 getImg: false, 112 isEnter: false, 113 file: "null", 114 description: "", 115 }; 116 this.surveys.push(item); 117 } 118 }, 119 // 現地調査報告を登録 120 storeSurvey: function () { 121 let formData = new FormData(); 122 let fileCount = 0 123 // 現場調査報告をforEach分で全て取得する 124 this.surveys.forEach((survey) => { 125 formData.append("descriptions[]", survey.description); 126 formData.append("images[file][]", survey.file); 127 if (survey.file != "null") { 128 fileCount++ 129 } 130 }); 131 // 何も登録されていない場合のエラー処理 132 if (fileCount <= 0) { 133 alert("報告書が作成されてないので送信できません。") 134 return 0 135 } 136 // SMS送信処理 137 formData.append( 138 "is_send_to_project_orderer", 139 this.is_send_to_project_orderer 140 ); 141 // 備考及び現場調査報告IDの処理 142 formData.append("remark", this.remark); 143 formData.append("project_id", this.project_id); 144 // 画像処理する際のコマンド 145 let config = { 146 headers: { 147 "content-type": "multipart/form-data", 148 }, 149 }; 150 // 現場調査報告登録API 151 axios 152 .post("/api/surveys", formData, config) 153 .then((result) => { 154 // 登録後、完了画面へ遷移 155 location.href = this.urlPrefix + "/projects/survey/" + this.project_id + "/complete"; 156 }) 157 .catch((result) => { 158 errorHandling.errorMessage(result); 159 }); 160 }, 161 }; 162</script>

php

1/app/app/Http/Controllers/Api/SurveysController.php 2 3class SurveysController extends ApiBaseController 4{ 5 public function store(SurveyRequest $request) 6 { 7 \DB::transaction(function () use ($request) { 8 // 現地調査を登録 9 $project = Project::find($request->project_id); 10 $project->is_surveyed = 1; 11 $project->surveyed_at = Carbon::now(); 12 $project->save(); 13 $survey = new Survey; 14 $survey->is_send_to_project_orderer = $request->is_send_to_project_orderer == "true" ? true : false; 15 $survey->remark = $request->remark !== "null" ? $request->remark : null; 16 $survey->url = ''; 17 $survey->project_label = $project->projectLabel->id; 18 $survey->save(); 19 $survey->url = '/progress/survey/' . $survey->id; 20 $survey->save(); 21 22 $url = null; 23 foreach ($request['images']['file'] as $index => $image) { 24 // ファイルをアップロード 25 // $url = $image->store('surveys'); 26 $url = $image->store('public/img/surveys'); 27 // $url = $image->store('img/surveys'); 28 $surveyImage = new SurveyImage; 29 $surveyImage->img = $url; 30 $surveyImage->description = $request['descriptions'][$index] !== "null" ? $request['descriptions'][$index] : null; 31 $surveyImage->survey_id = $survey->id; 32 $surveyImage->save(); 33 } 34 // ショートメッセージを送信 35 if ($project->user->enable_sms) { 36 if ($request->is_send_to_project_orderer == "true") { 37 $type = config('const.sms.type.survey'); 38 $message = 39$project->projectOrderer->company.' 様 40SMS送信 41'.route('sponsor.index'); 42 SmsService::sendToProjectOrderer($project->id, $type, $message); 43 } 44 } 45 }); 46 return response()->noContent(); 47 }

試したこと

1.シンボリックリンク作成
php artisan storage:link
2.キャッシュクリア
php artisan cache:clear php artisan config:clear php artisan route:clear php artisan view:clear composer dump-autoload php artisan clear-compiled php artisan optimize php artisan config:cache
3.filesystems.php確認済み
/app/config/filesystems.php <?php return [ ~~~~ 'links' => [ public_path('storage') => storage_path('app/public'), // public_path('storage') => storage_path('public'), ], ];

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

Laravel Framework 7.30.4

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

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

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

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

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

phper.k

2021/05/25 04:08 編集

表示したい時に使っているコードが間違っている可能性は?
m.ts10806

2021/05/25 04:27

コードは一通り提示してください。提示された箇所以外が問題ないという根拠がないです。
nanami0221

2021/05/25 04:44

申し訳ございません、以下2つを追記しました。 Vueファイル(ProjectRegisterComponent.vue) APIファイル(SurveysController.php)
guest

回答1

0

ベストアンサー

<img src="/assets/img/icon_batu_white.png">

これに限らずアプリケーション内のURLはフレームワークの機能を使って生成されたほうが間違いないです。

ヘルパ:URL

投稿2021/05/25 04:48

m.ts10806

総合スコア80875

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

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

nanami0221

2021/05/28 05:57

ご丁寧にありがとうございますm(_ _)m 以下で解決できたため、終了させていただきます! 1.storageを削除する 2.シンボリックリンクを再度作成 3.キャッシュクリア なぜかシンボリックリンクがファイルになっておりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問