【Rails】Carrierwaveで画像アップロード
こんにちは。ぺんぎんです。
今回はユーザー登録や投稿の時に使う、画像アップロード機能を実装していきたいと思います。
railsの便利なライブラリ、Carrierwaveを使えば簡単に画像アップロード機能を実装することができます。
Carrierwaveとは
Railsにおける画像アップロード用のgem。
Carrierwaveでは、アップロード機能用のアップローダークラスを作って、細かい設定を書いていきます。
そのため個別のモデルに依存しないで、柔軟にいろいろな設定をすることができます。
手順
1. gemをインストール
Gemfile
gem 'carrierwave' fem 'minimagick'
今回は画像をリサイズできるようにminimagickもインストールします。 minimagickにはImageMagickが必要になります。 インストール方法はこちら。
ターミナル
bundle install
bundle installしたらサーバーを再起動させます。
2. アップローダーを生成する
$ bundle exec rails g uploader アップローダー名
$ bundle exec rails g uploader Image
→app/uploaders/image_uploader.rbというファイルが生成されます。
3. 生成されたアップローダーに設定を記述する
- デフォルト画像
- アップロード可能なファイルの種別 デフォルトで入っているコメントは消してOK。
4. ローカル環境でアップロードした画像をアップロードしないように設定する
保存した画像はgithubなどにあげて共有する必要はないですよね。
そこで、.gitignoreファイルに画像の保存先を指定して、プッシュされないように設定しましょう。
.gitignore
/public/uploads
この設定をしないでプッシュてしまった人はこちら。
5. boardsテーブルに画像のカラムを追加する
progateで学んだ人もいると思いますが、画像はDBに直接保存するわけではありません。
DBの容量がパンクしないように、画像名のカラムを作って保存するようにします。
$ bundle exec rails g migration AddImageToBoards image:string $ bundle exec rails db:migrate
これでboardsテーブルに画像用のimageカラムができました。
6. モデルでアップローダークラスとカラムの紐付け
先ほど作ったアップローダークラスは、今のままではBoardクラスとバラバラになっているので、Boardモデルでアップローダークラスを紐づけておきましょう。
class モデル名 < ActiveRecord::Base mount_uploader [:カラム名], [アップローダークラス] end
class Board < ApplicationRecord mount_uploader :image, ImageUploader end
ちなみにmountはよく耳にするあの「マウンティング」と同じ言葉です。
もともと「乗る」という意味で「据え付ける」という意味もあります。
7. コントローラでparamsに画像アップロード用カラムの追加
BoardコントローラではBoard.newで新しい掲示板を作っています。
paramsで受け取れるように、画像用カラムを追加します。
def create @board = Board.new(board_params) end def board_params params.require(:board).permit(:title, :body, :image) end
8. Viewに画像ファイルのフィールドを追加する
- 投稿フォーム
画像ファイルを送信する際のファイル選択ボックスを生成します。
ラベル部分はあとでi18nで日本語を定義します。
<%= f.label :カラム名 %> <%= f.file_field :保存されるカラム %>
app/views/boards/_form.html.erb
<%= form_with model: board, local: true do |f| %> <%= render 'shared/error_messages', object: f.object %> <div class="form-group"> <%= f.label :image %> <%= f.file_field :image, class: 'form-control mb-3', accept: 'image/*' %> <%= f.hidden_field :board_image_cache %> </div> <%= f.submit class: 'btn btn-primary' %> <% end %>
accept属性で選択できるファイルの種類を指定します。
これを指定しないと選択画面でどんなファイルも選択できてしまいます。
「image/*」は画像ファイル全般を指します。
また<%= f.hidden_field :board_image_cache %>を入れておくと、バリデーションエラーになった後でも、データが引き継がれ情報を再入力する手間が省けます。
【Rails】CarrierwaveのCache機能を使用し、バリデーション後の画像データを保持する方法
- 画像表示
アップロードした画像を表示させます。
image_tagの使い方
<%= image_tag 'ファイル名', 'オプション' %>
ここではファイル名の代わりに、アップローダークラスのurlメソッドを使って、ファイルのURLを取得するようにします。
app/views/boards/_board.html.erb
<%= image_tag board.image_url, class: 'card-img-top', size: '300x200' %>
画像がない場合にデフォルト画像を表示させたい人はこちらを見てください。
【Rails】image_tagを使って簡単に画像を表示させよう!
9. i18nで翻訳を定義する
・imageカラムの日本語を定義します。
config/locales/activerecord/ja.yml
ja: activerecord: attributes: board: title: 'タイトル' body: '本文' image: 'サムネイル'
・画像に関するメッセージの日本語を定義する
Carrierwaveですでに用意されているバリデーションのエラーメッセージを日本語にします。
Carrierwave用の定義ファイルを用意しましょう。
config/locales/carrierwave/ja.yml
ja: errors: messages: carrierwave_processing_error: '処理できませんでした' carrierwave_integrity_error: 'は許可されていないファイルタイプです' carrierwave_download_error: 'はダウンロードできません' extension_whitelist_error: "は %{allowed_types}の形式でアップロードしてください" extension_blacklist_error: "%{extension}ファイルのアップロードは許可されていません。アップロードできないファイルタイプ: %{prohibited_types}" content_type_whitelist_error: "%{content_type}ファイルのアップロードは許可されていません。アップロードできるファイルタイプ: %{allowed_types}" content_type_blacklist_error: "%{content_type}ファイルのアップロードは許可されていません" rmagick_processing_error: "rmagickがファイルを処理できませんでした。画像を確認してください。エラーメッセージ: %{e}" mini_magick_processing_error: "MiniMagickがファイルを処理できませんでした。画像を確認してください。エラーメッセージ: %{e}" min_size_error: "を%{min_size}以上のサイズにしてください" max_size_error: "を%{max_size}以下のサイズにしてください"
いろいろな設定
アップローダークラスでいろいろな設定をしましょう。
* アップロードしたファイルの保存場所
アップロードされた画像の保存場所は、デフォルトで「public/uploads/モデル名/画像カラム名/id」に設定されています。
class ImageUploader < CarrierWave::Uploader::Base def store_dir "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" end end
今回の場合は「public/uploads/board/image/id」に保存されます。
この「id」には掲示板のidが入るので、board.idが1の掲示板で画像をアップロードしたら、「public/uploads/board/image/1」というフォルダに保存されます。
* 画像がない場合のデフォルト画像の指定
class ImageUploader < CarrierWave::Uploader::Base def default_url 'sample.png' end end
これを設定しておけば、画像がない時とある時でView側で条件分岐をしなくてすみます。
* アップロードできる拡張子の指定
def extension_whitelist %w(jpg jpeg gif png) end
gitignoreを設定をしないでgitでコミットしてしまった場合
コミット後にこれを追記しても、アップロード済みのファイルは変更されません。 コミット後はファイル名を指定してgitの管理対象外に変更します。
git rm --chached ファイル名
また不要なファイルをpushしてしまった場合は、リモートリポジトリから削除します。
git rm ファイル名
必ずpush前に不要なファイルがないか確認しましょう( ^ω^ )
参照
CarrierWave github.com
【Rails】CarrierWaveチュートリアル pikawaka.com