3
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

carrierwaveでmultiple: trueは相性が悪い?

Last updated at Posted at 2019-11-28

はじめに

Railsを使って某フリマアプリのクローンを作成する際、一つの商品に対して複数の写真投稿が可能な場合の処理に手こずったため、何かの参考になればと思い投稿します。

今回行ったこと

単純なアプリケーションを作って流れなどを理解しやすくし、fields_forを用いた形でのパラメーターの動きやcarriewaveで複数画像をアップロードする際の必要な記述に気を配りながら検証を行った。

環境

Rails 5.0.7.2
Ruby 2.5.1

アプリケーションの設計

テーブル

今回は以下のような単純な設計のアプリケーションを作成しました。
一つのツイートが複数の写真を持つことができるようになっています。

tweet
content
image
url
tweet_id

Gemのインストール

今回インストールするGemはこれだけです。hamlは現在使い慣れているものなので導入しています。

Gemfile
gem 'carrierwave'
gem 'mini_magick'
gem 'haml-rails'

モデルファイル

親モデルに当たるtweetモデルにはaccepts_nested_attributes_forの記述をします。これはtweetモデルと同時にimageモデルへも同時に作成するのに必要な記述です。
子モデルのimageモデルにはmount_uploaderで指定したカラムに対してのアップロード先を指定してあげます。image_uploaderの作成も忘れずに。

models/tweet.rb
class Tweet < ApplicationRecord
  has_many :images
  accepts_nested_attributes_for :images
end
models/image.rb
class Image < ApplicationRecord
  belongs_to :tweet, optional: true
  mount_uploader :url, ImageUploader
end

投稿フォーム

tweets/new.html.haml
.contents
  = form_for @tweet do |f|
    = f.label :content, "テキスト"
    = f.text_area :content, placeholder: "ツイート"
    .file
    = f.fields_for :images do |c|
      = c.label :url, '画像'
      = c.file_field :url
    .submit
      = f.submit "投稿", {class: "btn"}

fields_forを使用することで、tweetの属性と同時にimageの属性もフォームを送ることができます。

コントローラー

tweets_controller.rb
class TweetsController < ApplicationController
  #投稿結果がわかるようにindexに全て表示させています。
  def index
    @tweets = Tweet.includes(:images).all
  end

  #ここから
  def new
    @tweet = Tweet.new
    2.times{@tweet.images.build}
  end

  def create
    @tweet = Tweet.new(tweet_params)
    @tweet.save
    if @tweet.save
      redirect_to action: "index"
    else
      render "new"
    end

  end

  private

  def tweet_params
    params.require(:tweet).permit(
      :content,
      images_attributes: [:url]
    )
  end
end

newアクション内の@tweet.images.buildはtweetにネストしたimageを定義しておくものです。2.timesとすることでビュー側で画像アップロードのフォームが二つ生成されます。
また、ストロングパラメーターをimages_attributes: [:url]とすることで、imageの属性値を配列で受け取るようにします。

フォーム画面

このような見た目になるので、テキストと画像を選択すれば投稿ができます。画像が一つだけでも大丈夫でした。
スクリーンショット 2019-11-29 2.01.48.png

multiple: trueを記述する方法はcarrierwaveと相性が悪い?

ここでタイトルにもある内容に入るのですが、私はこの部分にかなり苦戦させられてしまいました。
というのも、画像を複数投稿する方法に関する記事をまわって情報を集めていたのですが、フォームのfile_fieldmultiple: trueという記述を書くことで複数投稿ができるということだったのですが、私はこの方法ではどうにもうまくいかず質問させていただいたところ、carrierwaveでmultiple: trueの記述を用いるのはあまり好ましくないとのことでした。
ただ、それで複数投稿が不可能ではないのでゴリ押しでできてしまうこともあるらしいです。

models/image.rb
# 修正前
class Image < ApplicationRecord
  belongs_to :tweet, optional: true
  mount_uploaders :url, ImageUploader
end



# 修正後
class Image < ApplicationRecord
  belongs_to :tweet, optional: true
  mount_uploader :url, ImageUploader
end
tweets/new.html.haml
# 修正前
= f.fields_for :images do |c|
  = c.label :url, '画像'
  = c.file_field :url, multiple: true



# 修正後
= f.fields_for :images do |c|
  = c.label :url, '画像'
  = c.file_field :url

修正前の記述の状態でずっと検証を行っていたのですが、配列としてうまくパラメータが送られてこず、undefined method ‘map'と言われていました。

おわりに

もともと私のパラメーター周りの知識が少なかったこともあり、かなり苦戦した経験の一つとなりました。また、今回のような記事を見つけられなかったため、もし似た状況で困っている方の手助けになれば幸いです。
当方、まだまだ実務経験のない初学者のため、誤った認識の箇所などご指摘いただけたらと思います。

#今回参考にさせていただいた記事
https://qiita.com/katsu105/items/83977a7b2b4437caa2e2
https://qiita.com/sinagaki58/items/a0d59cc41c6824bb5f67

3
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?