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

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

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

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

Q&A

解決済

1回答

766閲覧

【Ruby】ActiveStrageを使った複数画像の投稿と、投稿した画像の全件表示がしたい

kawanoonigiri

総合スコア14

Ruby

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

0グッド

0クリップ

投稿2021/08/18 08:51

編集2021/08/21 04:30

前提・実現したいこと

現在railsを使ってポートフォリオを作成しています。
よくあるクチコミサイトのようなサイトで、1つの店舗に対して複数画像が投稿できる機能を実装しているところです。

ActiveStrageを使い、1枚のみの保存・表示はできています。

今実現したい点は2つあります。
①投稿済みの画像を複数表示させたい。
②画像の投稿をできるようにしたい。
です。

情報不足であれば追加いたします。
よろしくお願いいたします。

現在発生しているエラー

エラー表示は出ていません。
投稿フォームの画像選択のほか全ての項目を埋め、送信ボタンを押すとバリデーションを通過できずにnewページがレンダリングされます。

該当のソースコード

  
下記はトップページのviewです。

ruby

1 <div class="messages"> 2 <% store.images.each do |image| %> 3 <%= link_to image_tag( image, class: :card__img), store_path(store) %> 4 <% end %> 5 </div>

  
こちらは詳細ページのviewです。

ruby

1 <% @store.images.each do |image| %> 2 <div class="store__image"> 3 <%= image_tag image, alt: '店舗画像' %> 4 </div> 5 <% end %>

  
こちらはstore.rb内の記述です。(バリデーションの記述が長いので一部省略しています。)

ruby

1 has_many :comments, dependent: :destroy 2 has_many :goods, dependent: :destroy 3 belongs_to :user 4 has_many_attached :images 5 6 with_options presence: true do 7 validates :name, (中略) ,:bgm, :images 8 end

  
下記はstores_controller.rb内の記述です。

ruby

1class StoresController < ApplicationController 2 def index 3 @store = Store.includes(:user) 4 end 5 6 def new 7 @store = Store.new 8 end 9 10 def create 11 @store = Store.new(post_params) 12 binding.pry 13 if @store.valid? 14 @store.save 15 redirect_to root_path 16 else 17 render :new 18 end 19 end 20 21 def show 22 @comment = Comment.new 23 @store = Store.find(params[:id]) 24 @comments = @store.comments.includes(:user) 25 end 26 27 def edit 28 @store = Store.find(params[:id]) 29 end 30 31 def update 32 @store = Store.find(params[:id]) 33 if @store.update(post_params) 34 redirect_to store_path(@store) 35 else 36 render :edit 37 end 38 end 39 40 def destroy 41 @store = Store.find(params[:id]) 42 @store.destroy 43 redirect_to root_path 44 end 45 46 private 47 def post_params 48 params.require(:store).permit(:name, :address, :postal_code, :telephone, :url, :closing_day, :business_hour, :fee, :water, :temperature, 49 :roryu_status, :roryu_time, :air_bath, :break_place, :television, :bgm, :water_depth, images: [] ).merge(user_id: current_user.id) 50 end 51end

  
以下投稿フォームの記述です。

ruby

1<%= form_with model: store, local: true do |f|%> 2 <div class="field"> 3 <%= f.label :name, "店舗名" %><br /> 4 <%= f.text_field :name, class: :form__text, id:"store_title" %> 5 </div> 6 7 <div class="field"> 8 <%= f.label :postal_code, "郵便番号" %><br /> 9 <%= f.text_field :postal_code, class: :form__text, id:"store_catch_copy" %> 10 </div> 11 12 <div class="field"> 13 <%= f.label :address, "住所" %><br /> 14 <%= f.text_field :address, class: :form__text, id:"store_concept" %> 15 </div> 16 17 <div class="field"> 18 <%= f.label :telephone, "電話番号" %><br /> 19 <%= f.text_field :telephone, class: :form__text, id:"store_image" %> 20 </div> 21 22 <div class="field"> 23 <%= f.label :url, "公式HP" %><br /> 24 <%= f.text_field :url, class: :form__text, id:"store_concept" %> 25 </div> 26 27 <div class="field"> 28 <%= f.label :closing_day, "店休日" %><br /> 29 <%= f.text_field :closing_day, class: :form__text, id:"store_concept" %> 30 </div> 31 32 <div class="field"> 33 <%= f.label :business_hour, "営業時間" %><br /> 34 <%= f.text_field :business_hour, class: :form__text, id:"store_concept" %> 35 </div> 36 37 <div class="field"> 38 <%= f.label :fee, "入浴料" %><br /> 39 <%= f.text_field :fee, class: :form__text, id:"store_concept" %> 40 </div> 41 42 <div class="field"> 43 <%= f.label :roryu_status, "ロウリュ" %><br /> 44 <%= f.text_field :roryu_status, class: :form__text, id:"store_concept" %> 45 </div> 46 47 <div class="field"> 48 <%= f.label :roryu_time, "ロウリュの時間" %><br /> 49 <%= f.text_field :roryu_time, class: :form__text, id:"store_concept" %> 50 </div> 51 52 <div class="field"> 53 <%= f.label :temperature, "サウナ室内の温度" %><br /> 54 <%= f.text_field :temperature, class: :form__text, id:"store_concept" %> 55 </div> 56 57 <div class="field"> 58 <%= f.label :television, "サウナ室内のテレビ設置" %><br /> 59 <%= f.text_field :television, class: :form__text, id:"store_concept" %> 60 </div> 61 62 <div class="field"> 63 <%= f.label :water, "水風呂" %><br /> 64 <%= f.text_field :water, class: :form__text, id:"store_concept" %> 65 </div> 66 67 <div class="field"> 68 <%= f.label :water_depth, "水深" %><br /> 69 <%= f.text_field :water_depth, class: :form__text, id:"store_concept" %> 70 </div> 71 72 73 <div class="field"> 74 <%= f.label :air_bath, "外気浴" %><br /> 75 <%= f.text_field :air_bath, class: :form__text, id:"store_concept" %> 76 </div> 77 78 <div class="field"> 79 <%= f.label :break_place, "インターバル" %><br /> 80 <%= f.text_field :break_place, class: :form__text, id:"store_concept" %> 81 </div> 82 83 <div class="field"> 84 <%= f.label :bgm, "サウナ内BGM" %><br /> 85 <%= f.text_field :bgm, class: :form__text, id:"store_concept" %> 86 </div> 87 88 <div class="field" > 89 <%= f.label :images, "店舗画像" %><br /> 90 <%= f.file_field :images, id: "message_image", multiple: true %> 91 <div id="image-list"></div> 92 </div> 93 94 <div class="actions"> 95 <%= f.submit "登録する", class: :form__btn %> 96 </div> 97<% end %>

下記、プレビュー機能を実装したJavaScriptのコードです。

javascript

1document.addEventListener('DOMContentLoaded', function() { 2 if (document.getElementById('store_image')){ 3 const ImageList = document.getElementById('image-list') 4 5 const createImageHTML = (blob) => { 6 const imageElement = document.createElement('div') 7 imageElement.setAttribute('class', "image-element") 8 let imageElementNum = document.querySelectorAll('.image-element').length 9 10 const blobImage = document.createElement('img') 11 blobImage.setAttribute('src', blob) 12 13 const inputHTML = document.createElement('input') 14 inputHTML.setAttribute('id', `store_image_${imageElementNum}`) 15 inputHTML.setAttribute('name', 'store[images][]') 16 inputHTML.setAttribute('type', 'file') 17 18 imageElement.appendChild(blobImage) 19 imageElement.appendChild(inputHTML) 20 ImageList.appendChild(imageElement) 21 22 inputHTML.addEventListener('change', (e) => { 23 file = e.target.files[0]; 24 blob = window.URL.createObjectURL(file); 25 26 createImageHTML(blob) 27 }) 28 } 29 30 document.getElementById('store_image').addEventListener('change', (e) => { 31 let file = e.target.files[0]; 32 let blob = window.URL.createObjectURL(file); 33 34 createImageHTML(blob) 35 }); 36 }; 37});

試したこと

モデル内のバリデーションにて:imagesのみ削除し、画像なしで投稿できるか試してみたところその他の情報は正しく保存され、またローカル環境でも正しく表示されていました。

(追記)
Stores_controller.rb内のcreateアクションにて取得したparamsの中身を確認したところ、下記のように添付した画像2つは取得できているように思います。
しかしデータベースに保存されている画像は1枚のみです。

<ActionController::Parameters {"authenticity_token"=>"CuKTE0J3Va0ohKVkCyvbutsgYI08W5k42v9ybDmbb2d5xGiU6yueUvWuVFH8NF02uPkilKl16TooYEPLanjNqA==", "store"=><ActionController::Parameters {"name"=>"熱い湯", "postal_code"=>"123-4567", "address"=>"県", "telephone"=>"無", "url"=>"無", "closing_day"=>"無", "business_hour"=>"無", "fee"=>"200", "roryu_status"=>"無", "roryu_time"=>"無", "temperature"=>"100", "television"=>"無", "water"=>"10", "water_depth"=>"100", "air_bath"=>"無", "break_place"=>"無", "bgm"=>"無", "images"=>[#<ActionDispatch::Http::UploadedFile:0x00007fa67a60c048 @tempfile=# <Tempfile:/var/folders/8c/bzvqv8g14h9fsrkg93q1kjx40000gn/T/RackMultipart20210820-1656-4p688y.png>, @original_filename="200x200.png", @content_type="image/png", @headers="Content-Disposition: form-data; name=\"store[images][]\"; filename=\"200x200.png\"\r\nContent-Type: image/png\r\n">]} permitted: false>, "message"=>{"images"=>[#<ActionDispatch::Http::UploadedFile:0x00007fa67a617bf0 @tempfile=# <Tempfile:/var/folders/8c/bzvqv8g14h9fsrkg93q1kjx40000gn/T/RackMultipart20210820-1656-7kbbi8.png>, @original_filename="200x200.png", @content_type="image/png", @headers="Content-Disposition: form-data; name=\"message[images][]\"; filename=\"200x200.png\"\r\nContent-Type: image/png\r\n">]}, "commit"=>"登録する", "controller"=>"stores", "action"=>"create"} permitted: false>

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

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

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

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

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

J_O

2021/08/18 12:22

・投稿フォームはどうなっていますか? ・記載のmodelとcontrollerはStoreクラスというこうでよかったですか? ・複数投稿はエラーが出ていますか?どこで躓いているか詳細を記載いただければと思います。
kawanoonigiri

2021/08/18 14:46

J_Oさん コメントありがとうございます。 投稿フォームのコードについて質問内に追記いたしました。 modelとcontrollerはおっしゃる通りStoreクラスです。 エラー文は出ておりません。投稿フォームの画像選択のほか全ての項目を埋め送信ボタンを押すと、バリデーションを通過できていないようでnewページがレンダリングされています。 追加情報が必要でしたら改めて対応いたします。 よろしくお願いいたします。
guest

回答1

0

ベストアンサー

投稿フォームですが、name属性を削除して、末尾にmultiple: trueを追記して試してみてください。

<div class="field" > <%= f.label :images, "店舗画像" %><br /> <%= f.file_field :images, id:"store_image", multiple: true %> <div id="image-list"></div> </div>

あと全体のコードどうなっているのかわからないのですが、
<%= form_with model: store, local: true do |f|%> のstoreでエラーにならないのかが少し気になりました、、、

投稿2021/08/18 22:24

J_O

総合スコア143

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

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

kawanoonigiri

2021/08/19 01:55 編集

ご対応ありがとうございます。 上記コードにて挙動の確認をした結果、2枚画像を添付して送信すると最初の1枚目が保存され2枚目は保存されていないようです。表示される画像もその1枚が表示されるという挙動になりました。 フォーム送信時のparamsの中身について追記しておりますので、もし参考になればご確認いただければと思います。
J_O

2021/08/19 15:10

パラメータがおかしいですね。 通常"store"=>{"images",,,,,になるはずなんですが、messageになってますね。先述したとおりname属性は削除されていますか? ただ、挙動としては一枚だけ登録されているのも不思議ですが、、、 form_withのコードとその紐づいているcontrollerのaction(おそらくnew_actionですかね?)を中略せずに載せてください。
kawanoonigiri

2021/08/20 09:09

度々のご対応、ありがとうございます。 ご指摘いただきましたコードについて質問内に追記しております。 また、パラメータの値がおかしいとのことですので再度name属性削除されているか確認の上、再取得したparamsの値を掲載しております。 よろしくお願いいたします。
J_O

2021/08/20 15:13

やっぱりパラメータがおかしいですね。 一つはちゃんと"store"=>{"images"=>,,で指定されていますが、もう一つの画像のパラメータが "message"=>{"images"=>,,,"になってますね。 ただ、"message"=>{"images"になっている原因は不明なんで、とりあえずname属性を無理やり指定して投稿できるか確認してください。 <%= f.file_field :images, name: "store[images][]", id:"store_image", multiple: true %>
kawanoonigiri

2021/08/21 04:31

ご指摘いただいた点修正の上投稿してみましたが、やはり反映されているのは1枚のみでした。 もしかすると画像プレビュー機能をJavascriptにて実装済みなのですが、そちらが影響しているかもしれないのでコードを追記いたしました。
J_O

2021/08/22 07:03

jsを全て削除して登録できればjsが原因ですね
kawanoonigiri

2021/08/22 10:42

ご指摘の通りjsが適用されないようコメントアウトの上動作確認したところ、複数枚での投稿ができました。 jsに関してはこれから中身の確認をしていきます。 数日に渡りお付き合いいただきましてありがとうございました。
J_O

2021/08/22 14:50

jsはあまり得意ではないので、 もし解決できなければ、再度新しく質問することをお勧めします!! お力になれずすみません、、、
kawanoonigiri

2021/08/23 00:06

ありがとうございます。 jsについては自力で解決できました! ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問