掲示板の画像アップロード機能
確認ポイント
・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属性を指定したので、ここで、画像を表示させる。
参考文献