0
0

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 1 year has passed since last update.

フォームオブジェクトでCarrierWaveを使うとアップロード先が…!

Last updated at Posted at 2022-05-21

はじめに

CarrierWaveでファイルをアップロードできるようにしたモデルから作ったフォームオブジェクトでファイルをアップロードすると、アップロード先が違ってしまい参照できなくなってしまいました。
少し工夫して参照できるようにしたので、同じようなことで困ってましたら、参考にしてください。

image.png
image.png

ソース

修正前: https://github.com/ken1flan/carrierwave_store_dir_sample
修正: https://github.com/ken1flan/carrierwave_store_dir_sample/pull/2

修正前のコード

Articleと、それを継承したForm::Articleというフォームオブジェクトがあったとします。

app/models/article.rb
class Article < ApplicationRecord
  mount_uploader :image, ImageUploader
end
app/models/form/article.rb
class Form::Article < Article
end

ArticleがマウントしているのはCarrierWaveのジェネレータで作ったままのものです。

app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  # include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  storage :file
  # storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  # この下は全部コメントだったので省略
end

フォームオブジェクトでファイルをアップロードすると参照できない

Form::Articleでレコードを作成すると、uploads/form/article以下にアップロードされてしまい…。

image.png

原因

ImageUploader#store_dirの実装を見てみると、クラス名をスネークケースにしたものをディレクトリ名に採用しているからでした。フォームオブジェクトだとその部分はform/articleになってしまいます。

app/uploaders/image_uploader.rb
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

修正

ApplicationRecordにモデル名をスネークケースにして返すメソッドを準備しておいて…

app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  primary_abstract_class

  def self.carrierwave_store_id
    to_s.underscore
  end
end

それを使うようにImageUploader#store_dirを書き換えて…

app/uploaders/image_uploader.rb
  def store_dir
    "uploads/#{model.class.carrierwave_store_id}/#{mounted_as}/#{model.id}"
  end

フォームオブジェクトでは'article'を返すようにオーバーライドするようにしました。

app/models/form/article.rb
class Form::Article < Article
  def self.carrierwave_store_id
    'article'
  end
end

結果

想定通りのディレクトリに保存できて、無事に参照できるようになりました。

image.png

image.png

おわりに

Rails5でモデルの継承元がActiveRecord::BaseからApplicationRecordに変わったのですが、これが地味に助かることが多くて…。
長く広く使われているフレームワークの強みを感じました。

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?