#環境
Ruby 2.5.1
Rails 5.2.4.3
#やりたい事
Rails標準のファイル管理機能Active Storageを使い、画像を複数を投稿・削除できる機能を実装したい。
###まずアプリを作成
$ rails new sample_app
$ cd sample_app
$ bin/rails db:create
別ターミナルで
$ bin/rails s
http://localhost:3000 にアクセスして馴染みの画像が出ていればOK。
###modelとcontrollerを作成
今回はpostという名前で。
$ bin/rails g model post name:string
$ bin/rails db:migrate
$ bin/rails g controller posts
###ルーティング
Rails.application.routes.draw do
resources :posts
end
###Active Storageをインストール
$ bin/rails active_storage:install
Copied migration 20200726095142_create_active_storage_tables.active_storage.rb from active_storage
以下の2つのテーブルを作成するマイグレーションファイルが作成される。
・active_storage_attachments
・active_storage_blobs
migrateしてテーブルを作成。
$ bin/rails db:migrate
== 20200726095142 CreateActiveStorageTables: migrating ========================
-- create_table(:active_storage_blobs)
-> 0.0020s
-- create_table(:active_storage_attachments)
-> 0.0019s
== 20200726095142 CreateActiveStorageTables: migrated (0.0041s) ===============
モデルと関連付けて使えるようにする
class Post < ApplicationRecord
has_many_attached :images
end
###controllerを記述
class PostsController < ApplicationController
def index
@posts = Post.all
end
def new
@post = Post.new
end
def create
@post = Post.new(post_params)
if @post.save
flash[:success] = "作成しました"
redirect_to posts_path
else
render :new
end
end
def destroy
@post = Post.find(params[:id])
@post.destroy
flash[:success] = "作成しました"
redirect_to posts_path
end
private
def post_params
params.require(:post).permit(:name, images: [])
end
end
###viewを作成
投稿一覧ページ
<h1>投稿一覧</h1>
<%= link_to '新規投稿', new_post_path %>
<%= render @posts %>
今回はpostのpartialを作って表示させる。
<div class="post-partial">
<li id="post-<%= post.id %>">
<%= post.name %>
<% post.images.each do |image| %>
<%= image_tag(image, width:100) %>
<% end %>
<%= link_to '削除', post, method: :delete, data: { confirm: '削除してよろしいですか?' } %>
</li>
</div>
###新規作成ページ
画像を複数投稿する場合はmultiple: trueが必要
<%= form_with(model: @post, local: true) do |f| %>
<div>
<%= f.label :name, '名前' %>
<%= f.text_field :title %>
</div>
<div>
<%= f.label :images, '画像' %>
<%= f.file_field :images, multiple: true %>
</div>
<div>
<%= f.submit '投稿する' %>
</div>
<% end %>
###ブラウザから http://localhost:3000/posts にアクセス
新規投稿から画像を複数投稿する事ができた。
##任意の画像を削除する
###controllerにメソッド追記
編集に必要なedit、updateメソッドを追記します。
def edit
@post = Post.find(params[:id])
end
def update
post = Post.find(params[:id])
if params[:post][:image_ids]
params[:post][:image_ids].each do |image_id|
image = post.images.find(image_id)
image.purge
end
end
if post.update_attributes(post_params)
flash[:success] = "編集しました"
redirect_to posts_url
else
render :edit
end
end
###投稿編集ページの作成
新規投稿ページとほぼ一緒だが、登録されている画像を表示しチェックを入れる部分を追記。
<%= form_with(model: @post, local: true) do |f| %>
<div>
<%= f.label :name, '名前' %>
<%= f.text_field :name %>
</div>
<div>
<%= f.label :images, '画像' %>
<%= f.file_field :images, multiple: true %>
</div>
<% if @post.images.present? %>
<p>現在登録されている画像(削除するものはチェックしてください)</p>
<% @post.images.each do |image| %>
<%= f.check_box :image_ids, {multiple: true}, image.id, false %>
<%= image_tag image, size:"100x100" %> <br>
<% end %>
<% end %>
<div>
<%= f.submit '編集する' %>
</div>
<% end %>
###indexに編集リンクを追記
<div class="post-partial">
<li id="post-<%= post.id %>">
<%= post.name %>
<% post.images.each do |image| %>
<%= image_tag(image, width:100) %>
<% end %>
<%= link_to '編集', edit_post_path(post.id) %> #追加
<%= link_to '削除', post, method: :delete, data: { confirm: '削除してよろしいですか?' } %>
</li>
</div>
###確認
ブラウザから編集のリンクをクリックし、削除したい画像にだけチェックを入れる。
任意の画像だけ削除できました。
#参考
ActiveStorageを使って複数画像管理をしてみる
ActiveStorage で画像を複数枚削除する方法