複数の画像登録機能(プレビュー機能付き)の作成手順を記載してみる。
環境
Mac High Sierra
ruby 2.5.1
Rails 5.2.1
実装したこと
複数画像をアップして表示する際の手順を記載してみる。
・index画面に画像一覧を表示させる
・new画面を用意する
・new画面でファイル選択した際の画像をプレビュー表示する
バリデーションやエラーチェックなどはあまり気にせず作成
最低限の機能ってことで、一覧、新規追加、削除しか搭載しない
前の記事をそれぞれ参考にして作成
RailsとVue.jsを使った簡単な項目追加機能
ActiveStorageを使った複数画像管理
1.rails new
rails newに--webpack=vueオプションを付けて、プロジェクトの作成時にVue.jsもインストールさせる
console
rails new image_sample --webpack=vue
記事作成時はsqlite3でエラーが出た
Error loading the 'sqlite3' Active Record adapter. Missing a gem it depends on? can't activate sqlite3 (~> 1.3.6), already activated sqlite3-1.4.0. Make sure all dependencies are added to Gemfile.
ので、Gemfileの編集をする
Gemfile
# Use sqlite3 as the database for Active Record
gem 'sqlite3', '~> 1.3.6'
2.active_storageインストール、マイグレーション
console
cd image_sample
rails active_storage:install
rails db:migrate
[マイグレーション結果]
active_storage_blobs,active_storage_attachmentsテーブルが作られる
== 2019030XXXXXXX CreateActiveStorageTables: migrating ========================
-- create_table(:active_storage_blobs)
-> 0.0027s
-- create_table(:active_storage_attachments)
-> 0.0124s
== 2019030XXXXXXX CreateActiveStorageTables: migrated (0.0153s) ===============
3.モデル作成、画像関連づけ
console
rails g model item name:string
rake db:migrate
app/models/item.rb
class Item < ApplicationRecord
has_many_attached :images
end
4.コントローラー作成
console
rails g controller items
5.ルーティング設定
config/routes.rb
Rails.application.routes.draw do
resources :items
end
6.コントローラー設定
app/controller/items_controller.rb
class ItemsController < ApplicationController
# item一覧
def index
@items = Item.all
end
# item新規作成
def new
@item = Item.new
end
# item作成
def create
@item = Item.new(item_params)
if @item.save
redirect_to items_path
else
render :new
end
end
# item削除
def destroy
@item = Item.find(params[:id])
@item.destroy
redirect_to items_path
end
private
def item_params
params.require(:item).permit(:name, images: [])
end
end
7.ビューの設定
一覧と新規作成画面を用意する。
一覧画面
app/views/items/index.html.erb
<h1>Items Index</h1>
<%= link_to 'Add item', new_item_path %>
<ul>
<% @items.each do |item| %>
<li>
<p><%= item.name %></p>
<p>
<% item.images.each do |image| %>
<%= image_tag(image, width:100) %>
<% end %>
</p>
<p>
<%= button_to '削除', item, method: :delete, data: { confirm: 'Are you sure?' } %>
</p>
</li>
<% end %>
</ul>
画像のサイズは一旦width:100で設定
新規作成画面
app/views/items/new.html.erb
<h1>Add Item</h1>
<%= form_with model: @item do |form| %>
<div>
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div>
<div id="image-app">
<%= form.file_field :images , class: "hidden" , "v-on:change": "onFileChange($event)", multiple: true %>
<ul v-if="images.length > 0">
<li v-for="(image, index) in images">
<button type="button" @click="removeThumbnail(image)">削除</button>
<img :src="image.thumbnail.url" width="150" height="150"/>
</li>
</ul>
</div>
<%= javascript_pack_tag 'image' %>
</div>
<div>
<%= form.submit %>
</div>
<% end %>
8.Vueの処理設定
構成
app/javascript配下に以下を設定
javascript
|_packs
|_image.js
packs/image.js
import Vue from 'vue'
new Vue({
el: '#image-app',
data: function() {
return {
images: [],
}
},
methods: {
//ファイル選択後イベント
onFileChange: function(ev) {
let files = ev.target.files || ev.dataTransfer.files;
let length = files.length;
if ( ! length) return;
for (var i=0; i<length; i++) {
this.viewThumbnail(files[i]);
}
},
// サムネイルを表示
viewThumbnail: function(file) {
var vm = this;
var reader = new FileReader();
reader.onload = function(ev){
var image = {
paths: [],
thumbnail: {
url: ev.target.result
},
};
vm.images.push(image);
};
reader.readAsDataURL(file);
},
// サムネイルを削除
removeThumbnail: function(image){
this.images.splice(this.images.indexOf(image), 1);
},
},
})
9.webpackのBuildをする
console
bin/webpack-dev-server
9.ローカルサーバー起動
console
rails s
9-1. http://localhost:3000/images にアクセス
9-2.item新規作成で画像を選択
9-3.Create_itemして一覧に遷移した後
前の記事のコピーに近くなったけど、プレビュー表示できたのでよかった。
その他
item削除でdatabase lockエラー
SQLite3のタイムアウトを変更する
config/database.yml
:
:
development:
<<: *default
database: db/development.sqlite3
# 追加
timeout: 1000
:
: