LoginSignup
5
2

More than 1 year has passed since last update.

Rails 掲示板の画像アップロード機能 carrierwave 解説

Last updated at Posted at 2021-12-16

Rails 掲示板の画像アップロード機能の実装 手順 (自分用)

アップロード用のライブラリ(carrierwave)をインストール

Gemfile
gem 'carrierwave'

・carrierwaveをgemに追加して、bundle install

ターミナル
$ bundle install

アップローダーを生成

ターミナル
$ bundle exec rails g uploader アップローダー名
ターミナル
$ bundle exec rails g uploader BoardImage

コマンドを実行すると、app/uploaders/board_image_uploader.rbファイルが作成される。

生成されたアップローダー

class BoardImageUploader < CarrierWave::Uploader::Base
  storage :file #アップロードファイルの保存場所を指定

  def store_dir #アップロードファイルの保存するディレクトリを指定
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  def default_url #デフォルトでっ表示する画像を指定。「app/assets/images」に保存した写真が使える。(最初は、sample.jpgが入っている)
    'board_placeholder.png'
  end

  def extension_whitelist #アップロードするファイルの許可する拡張子を指定
    %w(jpg jpeg gif png)
  end

end

・デフォルトでstorage :fileが指定されているので、アップロードしたファイルはpublic/配下に保存される。保存されるディレクトリは、store_dirで設定されるので、アップロードしたファイルは、「public/uploads」に保存される。

アップロード画像のカラムを追加

・アップロード画像の情報を保存するboard_imageカラムをboardsテーブル追加する為に、マイグレーションファイルを作成

ターミナル
$ bundle exec rails g migration AddBoardImageToBoards board_image:string
$ bundle exec rails db:migrate

・マイグレーションを実行して、boardsテーブルにboard_imageカラムを追加。

アップローダークラスとカラムの紐づけ

アップローダークラスとカラムの紐づけ
class モデル名 < ActiveRecord::Base
  mount_uploader [:カラム名], [アップローダークラス]
end

・投稿の際に画像も投稿する機能を追加したいので、boardモデルに先ほど作成した投稿画像用の「board_imageカラム」と「BoardImageUploaderクラス」を紐づける。

board.rb
class Board < ApplicationRecord
  mount_uploader :board_image, BoardImageUploader #追記
  belongs_to :user

  validates :title, presence: true, length: { maximum: 255 }
  validates :body, presence: true, length: { maximum: 65_535 }
end

・boardモデルで画像を投稿する際の「board_imageカラム」の設定を「BoardImageUploaderクラス」で行えるようになる。

boardコントローラーに設定しているストロングパラメーターに受け取るカラムを追加

app/controllers/boards_controller.rb
   def board_params
     params.require(:board).permit(:title, :body, :board_image, :board_image_cache)
   end

・「board_image」「board_image_cache」を追加。

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 :title %>
    <%= f.text_field :title, class: 'form-control' %>
  </div>
  <div class="form-group">
    <%= f.label :body %>
    <%= f.text_area :body, class: 'form-control', rows: 10 %>
  </div>
  <div class="form-group"> #ここから追記
    <%= f.label :board_image %>
    <%= f.file_field :board_image, class: 'form-control mb-3', accept: 'image/*' %>
    <%= f.hidden_field :board_image_cache %>
  </div>
  <div class='mt-3 mb-3'>
    <%= image_tag board.board_image.url,
                  id: 'preview',
                  size: '300x200' %>
  </div>    #ここまで

  <%= f.submit class: 'btn btn-primary' %>
<% end %>
<%= f.label :board_image %>

・「board_image」カラムの入力項目表示。jaファイルで名前変更可能。

<%= f.file_field :board_image, class: 'form-control mb-3', accept: 'image/*' %>

・「form.htmlタグ名 :カラム名」と指定する。カラム名は保存される先のテーブルのカラム名を指定するので、「board_image」を指定。これで、boardテーブルのboard_imageカラムに投稿した画像のデータが送られる。
・acceptでファイルの種類を指定。image/は画像ファイル全般。例えば、video/は動画ファイル全般。

<%= f.hidden_field :board_image_cache %>

・バリデーションに引っかかり、掲示板が登録できなかった時(エラーが出て入力画面に戻された時)に選んだ画像を保持しておく機能。(入力画面に戻された時に再度画像を選び直さなくていいように。)

掲示板の部分テンプレートに、アップロードした画像のURLを指定

app/views/boards/_board.html.erb
<div class="col-sm-12 col-lg-4 mb-3">
  <div id="board-id-<%= board.id %>">
    <div class="card">
      <%= image_tag board.board_image_url, class: 'card-img-top', size: '300x200' %> #追記
      <div class="card-body">
        <h4 class="card-title">
          <a href="#">
            <%= board.title %>
          </a>
        </h4>
        <div class='mr10 float-right'>
          <a href="#"><%= icon 'fas', 'trash', class: 'pr-1' %></a>
          <a href="#"><%= icon 'fa', 'pen' %></a>
        </div>
        <ul class="list-inline">
          <li class="list-inline-item">
            <%= icon 'far', 'user' %>
            <%= board.user.decorate.full_name %>
          </li>
          <li class="list-inline-item">
            <%= icon 'far', 'calendar' %>
            <%= l board.created_at, format: :long %>
          </li>
        </ul>
        <p class="card-text"><%= board.body %></p>
      </div>
    </div>
  </div>
</div>
<%= image_tag board.board_image.url, class:'card-img-top', size:'300x200' %>

・保存した画像(board_image)を表示させるには、画像が保存されている場所(パス)を取得する必要がある
・Boardモデルに、BoardImageUploaderクラスとboard_imageカラムを紐づけたことで「url」メソッドが使えるようになっている。
・「urlメソッド」 → ファイルのURLを取得 「使い方の例:boardモデル.board_image.url」
・「board.board_image.url」でBoardモデルのboard_imageカラムからurlを取得している。
*アップローダーでデフォルトで表示される画像を設定しているので、画像が設定されていないとういう事が起きないため、if,elseでの画像が設定されていなかったらなどの分岐は必要ない。

.gitignoreファイルの設定

・public/uploads/配下に保存される画像は、Githubなどにアップロードする必要がないので、以下のように.gitignoreファイルに/public/uploadsを指定してGit管理下から除外

.gitignore
/public/uploads
5
2
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
5
2