[RUBY] 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
Post videos 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
[Ruby on Rails] Upload multiple images with refile
[Implementation procedure] Implement image upload function with Active Storage
How to delete untagged images in bulk with Docker
[Rails 6] Add images to seed files (using Active Storage)
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
[Rails] Create API to download files with Active Storage [S3]