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

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

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

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails 7

Ruby on Rails 7は、2021年12月に正式リリースされました。Ruby on Railsのバージョン7であり、フロントエンド開発環境を大幅に刷新。Node.jsを用いない構成がデフォルトになっています。

Q&A

解決済

1回答

98閲覧

Ruby on Railsにて、すでに別の画像があるところに新しい画像のアップロードをしたい

sarucat

総合スコア1

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails 7

Ruby on Rails 7は、2021年12月に正式リリースされました。Ruby on Railsのバージョン7であり、フロントエンド開発環境を大幅に刷新。Node.jsを用いない構成がデフォルトになっています。

0グッド

0クリップ

投稿2024/12/04 07:08

実現したいこと

現在、口コミサイトのようなものを作成しています。
そこで最大3枚まで画像を付けられるように設計しております。

編集画面にて画像を変更したいとなった場合、下記を実現したいと考えております。
①すでに最初の投稿で画像をアップロードしていた場合はそのプレビュー表示と削除ができる。
②①で既存画像を削除した場合は新しい画像がアップロードできる。
③既存画像が1枚のみだった場合、残り2枚画像をアップロードできる。

発生している問題・分からないこと

現在、上記実現したいことのうち①と②は実装できたのですが、③のみができておりません。

既存画像が1枚ある状態の時に、既存画像のプレビュー表示はされている。また削除及び追加もできる。
既存画像が1枚ある状態の時に、新しい画像のアップロードをしようとすると画像選択はできるがプレビュー表示ができない。

エラーを見ると、「preview-container」のindexが正しく取れていないようなので、色々コードを書き換えてみたりしたのですがわからずじまいです。

エラーメッセージ

error

1Uncaught TypeError: Cannot read properties of undefined (reading 'querySelector')

該当のソースコード

html.erb

1<!-- 画像アップロード --> 2 <div class="row justify-content-center"> 3 <div id="file_input_container" class="mb-4"> 4 <p>写真を追加する(最大3枚まで)</p> 5 <div class="d-flex justify-content-start"> 6 <% @review.images.each_with_index do |image, index| %> 7 <div class="file-input-wrapper" data-controller="edit-preview"> 8 <!-- 既存画像のプレビュー --> 9 <div class="preview-container" data-edit-preview-target="preview" data-index="<%= index %>" style="display: block;"> 10 <%= image_tag url_for(image), alt: "Uploaded Image", class: "img-thumbnail" %> 11 </div> 12 <%= form.check_box :existing_image_ids, { multiple: true, id: "delete_checkbox_#{index}", class: "d-none" }, image.id, nil %> 13 <button type="button" class="delete-btn" data-action="click->edit-preview#delete" 14 data-edit-preview-target="deleteBtn" data-index="<%= index %>" style="display: block;">×</button> 15 <input type="file" name="review[images][]" accept="image/*" class="form-control-file" 16 data-edit-preview-target="fileInput" data-action="change->edit-preview#initializeFileInput" 17 data-index="<%= index %>" style="display: none;"> 18 <div class="plus-icon" data-edit-preview-target="plusIcon" data-index="<%= index %>" style="display: none;">+</div> 19 </div> 20 <% end %> 21 22 <!-- 新規画像 --> 23 <% remaining_images = 3 - @review.images.size %> 24 <% if remaining_images > 0 %> 25 <% remaining_images.times do |i| %> 26 <div class="file-input-wrapper" data-controller="edit-preview"> 27 <input type="file" name="review[images][]" accept="image/*" class="form-control-file" 28 data-edit-preview-target="fileInput" data-action="change->edit-preview#initializeFileInput" 29 data-index="<%= @review.images.size + i %>"> 30 <div class="plus-icon" data-edit-preview-target="plusIcon">+</div> 31 <div class="preview-container" data-edit-preview-target="preview" data-index="<%= @review.images.size + i %>" style="display: none;"> 32 <img src="" alt="Preview"> 33 </div> 34 <button type="button" class="delete-btn" data-action="click->edit-preview#delete" 35 data-edit-preview-target="deleteBtn" data-index="<%= @review.images.size + i %>" style="display: none;">×</button> 36 </div> 37 <% end %> 38 <% end %> 39 </div> 40 </div> 41 </div>

controller.js

1initializeFileInput(event) { 2 const input = event.target; 3 const index = input.dataset.index; 4 const file = input.files[0]; 5 6 console.log("Input index:", index); 7 console.log("Preview Targets:", this.previewTargets); 8 9 console.log("Preview Targets:", this.previewTargets); 10 console.log("Total previewTargets length:", this.previewTargets.length); 11 12 const previewContainer = this.previewTargets[index]; 13 const plusIcon = this.plusIconTargets[index]; 14 const deleteBtn = this.deleteBtnTargets[index]; 15 16 if (file) { 17 // ファイルが選択された場合、プレビューを表示 18 const reader = new FileReader(); 19 reader.onload = (e) => { 20 const img = previewContainer.querySelector('img'); 21 img.src = e.target.result; 22 23 plusIcon.style.display = 'none'; 24 previewContainer.style.display = 'block'; 25 deleteBtn.style.display = 'block'; 26 }; 27 28 reader.readAsDataURL(file); 29 } 30} 31

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

現在はソースコードを既存画像がある場合に応じて新規画像のアップロードフォームを増減する形にしていますが、それを最初からフォームを3つ作りその中で既存画像がある場合とない場合にわけたりしたソースコードも試しましたが、結果は同じでした。

補足

特になし

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

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

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

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

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

guest

回答1

0

自己解決

StimulusのTargetsはDOM順序を基準としているらしく、data-indexを使わず、Targetsの順序に依存する形に修正したところ動くようになりました。

投稿2024/12/04 13:08

sarucat

総合スコア1

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問