Railsの学習のためにゲームソフトのユーザーレビューサイトを制作しています。
環境は
Rails 5.2.4
Ruby 2.6.5
PostgreSQL
Docker Compose
です。
ユーザーがレビューを投稿する際に画像を投稿できる機能をActiveStorageで実装しようとしていて、投稿された画像に対してvalidateメソッドでバリデーションをかけたいのですがそれがうまくいきません。ActiveStorageの設定はhas_many_attached :imagesで行っています。
バリデーションの条件は
・画像が3枚以上添付されているとエラーになる。
・添付されたファイルのcontent_typeがimage/jpg image/jpeg image/gif image/pngのいずれかでなければエラーになる。
・画像1枚あたりの容量が2目がバイトより大きいとエラーになる。
です。
現在の状態は、file_fieldにcontent_typeがimage/jpgの画像を添付して送信するとレビューが正常に保存されて欲しいのですが、以下の画像のように「イメージはイメージファイルを指定して下さい」というエラーメッセージが表示されて保存されません。
関連するコードは以下の通りです。
review.rb
class Review < ApplicationRecord belongs_to :user belongs_to :game validates :user_id, presence: true validates :game_id, presence: true validates :user_id, uniqueness: { scope: :game_id, message: "は既にレビューを投稿しています" } validates :title, length: { maximum: 50 } validates :review, length: { maximum: 500 } validate :validate_score validate :validate_images has_many_attached :images #titleとreviewに値が入力されているreviewインスタンスを返す scope :review_with_value, -> { where.not(review: "").order(updated_at: "desc") } # scoreのバリデーション(1~10の数字以外はエラーになる) def validate_score regex = /[1-9]/ if score == nil || score == "" || !score.integer? errors.add(:score, "が正しくありません") elsif score.to_s.length == 1 if !score.to_s.match(regex) errors.add(:score, "が正しくありません") end elsif score.to_s.length >= 2 if score != 10 errors.add(:score, "が正しくありません") end end end # images画像のバリデーション def validate_images if images.count >= 3 images.purge errors.add(:images, "は2つまで指定できます") elsif !image_file? images.purge errors.add(:images, "はイメージファイルを指定して下さい") else case images.count when 1 then if images[0].byte_size > 2.megabytes images.purge errors.add(:images, "は2メガバイト以下の画像を指定して下さい") end when 2 then if images[0].byte_size > 2.megabytes || images[1].byte_size > 2.megabytes images.purge errors.add(:images, "は2メガバイト以下の画像を指定して下さい") end end end end # imagesで指定されたファイルがイメージファイルかどうかを調べる def image_file? case images.count when 1 then %w[image/jpg image/jpeg image/gif image/png].include?(images[0].content_type) when 2 then %w[image/jpg image/jpeg image/gif image/png].include?(images[0].content_type) && %w[image/jpg image/jpeg image/gif image/png].include?(images[1].content_type) end end end
_reviews_form.html.erb
<%= form_for @review, url: { action: yield(:action) } do |f| %> <%= render 'shared/error_messages', object: @review %> <div class="form-group"> <div><%= f.label :score %><span>(スコアだけ投稿できます)</span></div> <%= f.select :score, (1..10).to_a, {prompt: "スコアを選択してください"} , {class: "form-control", id: "score"} %> </div> <div class="form-group"> <%= f.label :title %> <%= f.text_area :title, class: "form-control", id: "title" %> </div> <div class="form-group"> <div><%= f.label :review %><span>(レビューを空欄にするとゲーム詳細ページにレビューが表示されません)</span></div> <%= f.text_area :review, class: "form-control", id: "review" %> </div> <div class="form-group"> <div><%= f.label :images %><span class="file_number">1</span></div> <%= f.file_field :images, multiple: true, class: "form-control", id: "file_field" %> </div> <div class="form-group"> <div><%= f.label :images %><span class="file_number">2</span></div> <%= f.file_field :images, multiple: true, class: "form-control", id: "file_field" %> </div> <%= hidden_field_tag(:game_id, @review.game_id) %> <%= f.submit yield(:button_text), class: "btn btn-success" %> <% end %>
reviews_controller.rb
class ReviewsController < ApplicationController before_action :find_resource, except: [:new, :create] before_action :logged_in_user, only: [:new, :create, :edit, :update, :destroy] def new @review = Review.new @review.game_id = params[:game_id] end def create @review = current_user.reviews.new(review_params) @review.game_id = params[:game_id] if @review.save flash[:success] = "レビューが投稿されました" redirect_to Game.find(params[:game_id]) else render "new" end end def show end def edit end def update if current_user == User.find(@review.user_id) if @review.update_attributes(review_params) flash[:success] = "レビューが更新されました" redirect_to game_path(@review.game_id) else render "edit" end else flash[:danger] = "このレビューは編集できません" redirect_to game_path(@review.game_id) end end def destroy if current_user == User.find(@review.user_id) if @review.destroy flash[:success] = "レビューが削除されました" redirect_to game_path(@review.game_id) else flash[:danger] = "レビューは存在しません" redirect_to game_path(@review.game_id) end else flash[:danger] = "このレビューは削除できません" redirect_to game_path(@review.game_id) end end private def review_params params.require(:review).permit(:score, :title, :review, images: []) end def find_resource @review = Review.find(params[:id]) end end
フォームを送信した時のログは以下の通りです。
Started POST "/reviews" for 172.18.0.1 at 2020-06-25 20:52:50 +0000 Cannot render console from 172.18.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255 Processing by ReviewsController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"93R7dbCejITKT8m6U9vsXGRwyoZFYkCdnuPorhrZQceJShF7CqiHjWeDZwqX2o61OP5ll6P600aQjNbYAROnWw==", "review"=>{"score"=>"5", "title"=>"", "review"=>"hoge", "images"=>[#<ActionDispatch::Http::UploadedFile:0x00007fac64326cd0 @tempfile=#<Tempfile:/tmp/RackMultipart20200625-1-fr3buu.jpg>, @original_filename="バイオ3.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"review[images][]\"; filename=\"\xE3\x83\x8F\xE3\x82\x99\xE3\x82\xA4\xE3\x82\xAA\xEF\xBC\x93.jpg\"\r\nContent-Type: image/jpeg\r\n">]}, "game_id"=>"4", "commit"=>"投稿"} [1m[36mUser Load (0.3ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2[0m [["id", 1], ["LIMIT", 1]] ↳ app/helpers/sessions_helper.rb:23 [36m Disk Storage (6.3ms) [0m[32mUploaded file to key: MKZwRH7SmEZbxnv6S2R9VzBX (checksum: NC1O8MLXS28QNfdAsUVu8g==)[0m [1m[35m (0.2ms)[0m [1m[35mBEGIN[0m ↳ app/controllers/reviews_controller.rb:11 [1m[36mActiveStorage::Blob Create (0.3ms)[0m [1m[32mINSERT INTO "active_storage_blobs" ("key", "filename", "content_type", "metadata", "byte_size", "checksum", "created_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"[0m [["key", "MKZwRH7SmEZbxnv6S2R9VzBX"], ["filename", "バイオ3.jpg"], ["content_type", "image/jpeg"], ["metadata", "{\"identified\":true}"], ["byte_size", 19053], ["checksum", "NC1O8MLXS28QNfdAsUVu8g=="], ["created_at", "2020-06-25 20:52:50.916214"]] ↳ app/controllers/reviews_controller.rb:11 [1m[35m (0.5ms)[0m [1m[35mCOMMIT[0m ↳ app/controllers/reviews_controller.rb:11 [1m[35m (0.2ms)[0m [1m[35mBEGIN[0m ↳ app/controllers/reviews_controller.rb:13 [1m[36mGame Load (0.2ms)[0m [1m[34mSELECT "games".* FROM "games" WHERE "games"."id" = $1 LIMIT $2[0m [["id", 4], ["LIMIT", 1]] ↳ app/controllers/reviews_controller.rb:13 [1m[36mReview Exists (0.4ms)[0m [1m[34mSELECT 1 AS one FROM "reviews" WHERE "reviews"."user_id" = $1 AND "reviews"."game_id" = $2 LIMIT $3[0m [["user_id", 1], ["game_id", 4], ["LIMIT", 1]] ↳ app/controllers/reviews_controller.rb:13 [1m[36mActiveStorage::Attachment Exists (0.3ms)[0m [1m[34mSELECT 1 AS one FROM "active_storage_attachments" WHERE "active_storage_attachments"."blob_id" = $1 LIMIT $2[0m [["blob_id", 61], ["LIMIT", 1]] ↳ app/models/review.rb:40 [1m[36mActiveStorage::Blob Destroy (0.4ms)[0m [1m[31mDELETE FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1[0m [["id", 61]] ↳ app/models/review.rb:40 [36m Disk Storage (0.5ms) [0m[31mDeleted file from key: MKZwRH7SmEZbxnv6S2R9VzBX[0m [36m Disk Storage (0.9ms) [0m[31mDeleted files by key prefix: variants/MKZwRH7SmEZbxnv6S2R9VzBX/[0m [1m[35m (0.2ms)[0m [1m[31mROLLBACK[0m ↳ app/controllers/reviews_controller.rb:13 Rendering reviews/new.html.erb within layouts/application Rendered shared/_error_messages.html.erb (0.9ms) Rendered reviews/_reviews_form.html.erb (14.8ms) Rendered reviews/new.html.erb within layouts/application (24.1ms) Rendered layouts/_header.html.erb (1.7ms) Completed 200 OK in 179ms (Views: 148.2ms | ActiveRecord: 2.9ms)
どこを修正すればいいかわからないのでアドバイスを頂きたいです。よろしくお願いします。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/06/27 09:27