Post / delete multiple images with Active Storage

environment

Ruby 2.5.1 Rails 5.2.4.3

What you want to do

I want to implement a function that can post / delete multiple images using Rails standard file management function Active Storage.

First create an app

$ rails new sample_app
$ cd sample_app 
$ bin/rails db:create

At another terminal

$ bin/rails s

If you access http: // localhost: 3000 and see a familiar image, it's OK.

スクリーンショット 2020-07-26 21.55.06.png

Create model and controller

This time with the name post.

$ bin/rails g model post name:string 
$ bin/rails db:migrate
$ bin/rails g controller posts

routing

config/routes.rb


Rails.application.routes.draw do
  resources :posts
end

Install Active Storage

$ bin/rails active_storage:install
Copied migration 20200726095142_create_active_storage_tables.active_storage.rb from active_storage

A migration file is created that creates the following two tables. ・ Active_storage_attachments ・ Active_storage_blobs Migrate to create a table.

$ 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) ===============

Make it available in association with the model

models/posts.rb


class Post < ApplicationRecord
  has_many_attached :images
end

Describe controller

controllers/posts_controller.rb


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] = "created"
      redirect_to posts_path
    else
      render :new
    end
  end

  def destroy
    @post = Post.find(params[:id])
    @post.destroy
    flash[:success] = "created"
    redirect_to posts_path
  end

  private

  def post_params
    params.require(:post).permit(:name, images: [])
  end
end

Create view

Post list page

erb:posts/index.html.erb


<h1>Post list</h1>
<%= link_to 'New post', new_post_path %>
<%= render @posts %>

This time, create a partial post and display it.

erb:posts/_post.html.erb


<div class="post-partial">
  <li id="post-<%= post.id %>">
    <%= post.name %>
    <% post.images.each do |image| %>
      <%= image_tag(image, width:100) %>
    <% end %>
    <%= link_to 'Delete', post, method: :delete, data: { confirm: 'Deleteしてよろしいですか?' } %>
  </li>
</div>

New page

Multiple: true is required when posting multiple images

erb:posts/new.html.erb


<%= form_with(model: @post, local: true) do |f| %>
  <div>
    <%= f.label :name, 'name' %>
    <%= f.text_field :title %>
  </div>

  <div>
    <%= f.label :images, 'image' %>
    <%= f.file_field :images, multiple: true %>
  </div>

  <div>
    <%= f.submit  'Post' %>
  </div>
<% end %>

Access http: // localhost: 3000 / posts from your browser

I was able to post multiple images from a new post.

スクリーンショット 2020-07-26 20.51.02.png

Delete any image

Add method to controller

Add the edit and update methods required for editing.

controllers/posts_controllers.rb


  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] = "Edited"
      redirect_to posts_url
    else
      render :edit
    end
  end

Creating a post edit page

It is almost the same as the new post page, but the part to display the registered image and check it is added.

erb:posts/edit.html.erb


<%= form_with(model: @post, local: true) do |f| %>
  <div>
    <%= f.label :name, 'name' %>
    <%= f.text_field :name %>
  </div>

  <div>
    <%= f.label :images, 'image' %>
    <%= f.file_field :images, multiple: true %>
  </div>

  <% if @post.images.present? %>
    <p>Currently registered images (check what you want to delete)</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  'To edit' %>
  </div>
<% end %>

Added edit link to index

erb:posts/index.html.erb


<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', edit_post_path(post.id) %>  #add to
    <%= link_to 'Delete', post, method: :delete, data: { confirm: 'Deleteしてよろしいですか?' } %>
  </li>
</div>

Verification

Click the edit link from your browser and check only the images you want to delete. スクリーンショット 2020-07-26 21.35.14.png

I was able to delete only any image.

スクリーンショット 2020-07-26 21.36.05.png

reference

Try managing multiple images using Active Storage How to delete multiple images with ActiveStorage

Recommended Posts

Post / delete multiple images with Active Storage
[Ruby on Rails] Delete s3 images with Active Strage
Rails Active Storage shrinks images before uploading
Introduce Active Storage
Upload multiple images easily with rails rails + carrierwave + cloudinary
How to link images using FactoryBot Active Storage
[Implementation procedure] Implement image upload function with Active Storage
How to delete untagged images in bulk with Docker
About DelegationError (Active Storage)
CarrierWave Upload multiple images
Active Storage Initialization Manual
Delete Active Admin resource
[Beginner] About Active Storage
Delete all Docker images
[Rails API + Vue] Upload and display images using Active Storage