前提・実現したいこと
現在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>
回答1件
あなたの回答
tips
プレビュー