Ryota400’s blog

エンジニアを目指して書いてます。

掲示板の画像アップロード機能

確認ポイント

・gemのインストール

gem  'carrierwave'
gem  'mini_magick'

CarrierWaveとは ファイルのアップロード機能を簡単に追加する事が出来るgem

Minimagickとは 画像に対して、画像同士を合成したり、リサイズしたりと編集することができるようになるためのgem

その後

bundle install

・Boardモデルのboardsテーブルにboard_imageカラムを追加する。

$ bundle exec rails g migration AddBoardImageToBoards board_image:string
$ bundle exec rails db:migrate

マイグレーションファイル

class AddBoardImageToBoards < ActiveRecord::Migration[5.2]
  def change
    add_column :boards, :board_image, :string
  end
end

画像を選択せずに掲示板を作成できるようにしたいので、マイグレーションファイルはそのままでNOTNULL制約はつけない

・画像uploaderの作成 次にcarrierwaveを利用するためのアップローダーを作成する。carrierwaveを導入したことで以下のコマンドが利用できるようになったので、ターミナルで実行する。

$ rails g uploader image ※imageの箇所は任意の名前でOKです。例:pictureなど
$ bundle exec rails g uploader BoardImage #今回の場合

生成されたアップローダーに、デフォルトの画像ファイルと、アップロード可能なファイル種別を指定する。

class BoardImageUploader < CarrierWave::Uploader::Base

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

  def default_url
    'board_placeholder.png'
  end

  def extension_whitelist
    %w(jpg jpeg gif png)
  end

end

アップローダーが作成できたので、画像アップロード機能を実装したいモデルに対して編集を行う。

 mount_uploader :image, ImageUploader
 mount_uploader :board_image, BoardImageUploader   #今回の場合

上記を追記することで、アップローダーを任意のモデルに対して マウントすることができました。 ※マウント 取り付ける、搭載するなどの意味

アップロード先のフォルダを、.gitignoreに登録する

/public/uploads

・ControllerとViewに、画像ファイルのフィールドを追加する app/controllers/boards_controller.rb

 def board_params
     params.require(:board).permit(:title, :body, :board_image, :board_image_cache)
 end

掲示板のフォームに、画像ファイルの入力フィールドを追加 app/views/boards/_form.html.erb

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

<%= image_tag board.board_image.url, id: 'preview', size: '300x200' %> プレビューを表示している。boardモデルのboard_imageのurlを呼び出し、表示する。

<%= f.hidden_field :board_image_cache %> これは、掲示板作成できなかった場合、アップロードした画像を消えないようにする処理する。

・JSファイルを設定する

javascriptの記載は、application.jsには記載せず、別の専用ファイルを作成する。 ここでは、application.jsは個別のJavaScriptを読み込む専用のファイルのため、preview.jsファイルを作成し記載する。

function previewFileWithId(id) {
    const target = this.event.target;
    const file = target.files[0];
    const reader  = new FileReader();
    reader.onloadend = function () {
        preview.src = reader.result;
    }
    if (file) {
        reader.readAsDataURL(file);
    } else {
        preview.src = '';
    }
}

const target = this.event.target; traget・・・操作を差し込む対象のオブジェクト event.target・・・最初にイベントが起こった要素です。今回だと、ファイルを選択した時のイベントを示す。

const file = target.files[0]; targetには「files」というプロパティが用意されています。 管理されているファイルは、「File」というオブジェクトの形をしています。 このFileオブジェクトには、ファイルに関する各種の情報や、ファイルアクセスのためのメソッドなどがまとめられている。 files[0]で一つ目のFileオブジェクトを取り出している

reader.onloadend = function () { preview.src = reader.result; } onloadend、FileReaderのイベント。データの読み込みが成功か失敗に関わらず終了した時にloadendイベントが発生し、ここに設定したコールバック関数が呼び出される。 そして、取得されたファイルの結果を、previewのsrc属性に指定している。

if (file) { reader.readAsDataURL(file); } else { preview.src = ''; } readAsDataURL()は、FileReaderのメソッドです。ファイルを、Data URIとして読み込むメソッド。例えば画像ファイルをこのメソッドで読み込んで、読み込んだデータをimg要素のsrc属性に指定すればブラウザに表示できる。 前文でscr属性を指定したので、ここで、画像を表示させる。

参考文献

qiita.com

qiita.com