概要
Railsで画像アップロードフォームを作成している時に、アップロードする画像を確認できるように表示する方法を調べました。
準備
Active Storageをインストール
$ rails active_storage:install $ rails db:migrate
ModelとMigrationを作成
$ rails g model Hoge
Model
今回は画像をimage
という名前で定義します。
# app/models/hoge.rb class Hoge < ApplicationRecord has_one_attached :image end
Migration
今回は画像アップロードだけなので他のカラムは作成しません。
# db/migrate/20230813122050_create_hoges.rb class CreateHoges < ActiveRecord::Migration[7.0] def change create_table :hoges do |t| t.timestamps end end end
Migrationファイルを適用させます。
$ rails db:migrate
Controller
# app/controllers/hoges_controller.rb class HogesController < ApplicationController def new @hoge = Hoge.new end def create @hoge = Hoge.new(hoge_params) if @hoge.save redirect_to root_path else render :new end end private def hoge_params params.require(:hoge).permit(:image) end end
Routes
Rails.application.routes.draw do root to: 'general#index' resources :hoges, only: [:new, :create] end
View
image_preview_controller.js
というJSファイルを使用するので、file_field
要素とサムネ表示部分の要素を<div data-controller='image-preview'>
要素で囲みます。
# app/views/hoges/new.html.erb <%= form_with model: @hoge, url: hoges_path, data: { turbo: false } do |f| %> <div data-controller='image-preview'> <% if @hoge.image.attached? %> <%= image_tag @hoge.image, id: 'img_prev' %> <% else %> <img id='img_prev'> <% end %> <br> <%= f.file_field :image, accept: 'image/jpeg,image/png', id: 'img_input', data: { action: 'change->image-preview#preview', target: 'image-preview.image' } %> </div> <%= f.submit '保存' %> <% end %>
JS
ファイル選択時に実行される関数を定義します。
// app/javascript/controllers/image_preview_controller.js import { Controller } from "@hotwired/stimulus" export default class extends Controller { preview(event) { const input = event.target if (input.files && input.files[0]) { const reader = new FileReader() const _this = this; reader.onload = (e) => { const image = new Image(); image.onload = function () { const imagePreview = _this.element.querySelector("#img_prev") imagePreview.src = e.target.result } image.src = e.target.result } reader.readAsDataURL(input.files[0]) } } }
これでファイルアップロードフォームにサムネを表示できるようになります。