[RUBY] I implemented the multiple image upload function in Rails so that multiple images can be slid for the post

1. Implemented multiple image upload function

I implemented it so that I can upload multiple images using carrierwave.

What is carrierwave?

carrierwave is a library that allows you to easily implement image upload functions from Rails applications. This time, I used carrierwave ver2.1.0.

How did you use it?

First, install the Gem below.

My app / Gemfile

gem 'carrierwave'
gem 'mini_magick'

Generate an uploader.

rails g upload image

This will generate the following files: If you want to customize in this file, add processing.

app/upload/image_upload.rb

So, I made the settings as below.

My app /app/upload/image_upload.rb

class ImageUploader < CarrierWave::Uploader::Base

    include CarrierWave::MiniMagick

    process resize_to_fill: [1000, 1000]

    version :thumb do
        process resize_to_fit: [223,223]
    end

    version :swiper do
        process resize_to_fit: [400, 400]
    end
    
    version :thumbnil do
        process resize_to_fit: [100, 100]
    end
    
    storage :file
    
    def store_dir
        "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
    end
    
     def extension_whitelist
        %w(jpg jpeg gif png)
     end
     
 end

How did you add the settings?

include CarrierWave::MiniMagick

I wanted to resize the image when uploading, so I installed minimagick. Since it is commented out when image_upload.rb is generated, # is deleted and it is described as a processing code. minimagick is a Ruby interface for imagemagick, a C program. This allows you to use methods for image resizing.

When uploaded, the process below cuts out at 1000x1000px, then a version called thumb is created and scaled to 223x223px. Similarly, versions called sweeper and thumbnil are created and scaled to each version.

This is where the image is saved when it is uploaded. The default is listed. It is placed like "public / uploads / specified model name / specified model column name / model ID / image and image created in each version". If you change it, you can overwrite it.

def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end

This is also commented out by default, so it is described so that it can be processed. You can specify a whitelist of allowed extensions. Uploading extensions other than jpg, jpeg, gif, and png will invalidate the record.

def extension_whitelist
    %w(jpg jpeg gif png)
end

This is the end of the explanation of the settings, and then the parent post table and the child image table are created. The table is divided into post and image in order to support multiple posts.

posts
content
images
url
post_id
$rails g model Post content:text 

$rails g model Image url:string post:reference

What I stumbled upon here was that in my case I handled the json type when creating the image model. Originally, I wanted to create a specification that allows multiple posts by creating an image column in the post table, but since I changed it to create a new image table and save it, I later learned that it is not necessary to make it a json type. I noticed. So, if you want to handle multiple images in one table here, you can use json type and design it so that you can handle multiple images in one object record. In my case, I created another table and left it as json type, but unless there is a specific reason, it is recommended to create it as string type.

Create a migration file and update the database.

$rails db:migrate

Add the following description to the model file.

My app /app/model/image.rb

class Image < ApplicationRecord
    belongs_to :post

mount_uploader: url, ImageUploader # Mount the data you want to use the upload function. end

My app /app/mode/post.rb

class Post < ApplicationRecord
    validates :content, presence: true, length: { maximum: 1000 }
    has_many :images, dependent: :destroy

If you post accepts_nested_attributes_for: images #post, you will be able to post images at the same time. end

It should be noted here that when using accepts_nested_attributes_for, the images_attributes column must be added to the strong parameter. It will be as follows.

My app /app/controller/post_controller.rb

  def new
    @post = Post.new
    @image = @post.images.build
  end
  
  def create
    @post = current_user.posts.new(post_params)
    if @post.save

redirect_to posts_path, success: "posted" else flash [: danger] = "Posting failed" render :new end end

  private
  
  def post_params
    params.require(:post).permit(:content, images_attributes: [:url])
  end

You have now set up to pass multiple images as parameters. Next, let's think about how to allow multiple images to be posted in view. Here, I was addicted to various things. In the fields_for method, it is said that multiple posts can be posted by describing multiple: true in the second argument, but it does not work ,. So, as another method, I implemented it so that multiple posts can be made with javascript. This article was written very well, so I used it as a reference. → Qiita If you set according to this article, javascript will start and the program should run every time you upload.

2. Implemented so that multiple images can be slid for one post with swipper

What is swiper?

Roughly speaking, it is a framework that makes it easy to implement the slide function.

How did you use it?

First, set up the sweeper to be used in the application. There are several methods, but I introduced it using yarn. The introduction method and contents of this article in yarn were very easy to understand, so I used it as a reference. →Qiita

Introduce swiper with yarn.

$yarn add swiper

$yarn install

Check packege.json to see if it was installed. If you have not installed yarn, install yarn with the following command. (If you are using mac)

$brew installl yarn

After installing, describe as follows in application.js and application.scss.

My app /app/assets/stylesheets/application.scss

@import "swiper/swiper-bundle";

My app /app/assets/javascript/application.js

 //= require swiper/swiper-bundle.js
 //= swiper.js

Create a swiper.js file and write as follows. With swiper, you need to write and create the kind of slide method you want to add with swiper. Choose your preferred slide method from the swiper demo and copy the js code in the script below!-Initialize Swiper-from the source code. Script tags do not need to be included. In my case, I made a slide with pagination / dynamic bullets, so it looks like this: This js file name does not have to be swipe.js. If you want to change the file name, also change the file name described in application.js. Demo

My app /app/assets/javascript/swiper.js

var swiper = new Swiper(".swiper-container", {
pagination: {
    el: ".swiper-pagination",
    dynamicBullets: true,
    },
});

Now that we're ready, let's actually implement it in view. Since it is an implementation example with pagination / dynamic bullet, if you choose another sliding method, please check the source code.

My app /app/views/posts/index.html.slim

 .swiper-container.top-carousel
    .swiper-wrapper(style="transform: translate3d(0px, 0px, 0px)")
         - @post.images.each do |img|
            .swiper-slide(style="width: 400px;")
                = link_to post do
                = image_tag img.swiper.url, class: "card-img-top"
     .swiper-pagination

~ Omitted ~

= javascript_include_tag "application"  

The important thing here is to write = javascript_include_tag "application" at the very end. If you forget to write this, sweeper will not start. You can write it in application.html.slim, but I write it only in the part of the page that requires sweeper. Also, this img.url.swiper.url calls the sweeper version of the image created by carrierwave.

You have now implemented swipe in your case.

Recommended Posts

I implemented the multiple image upload function in Rails so that multiple images can be slid for the post
I separated the same description as a method under private in Rails controller and implemented it so that it can be called by before_action
Multiple image upload function using Rails Carrierwave
Are you still exhausted to implement the search function? Gem'ransack' that can be implemented in an instant
[Rails + Webpacker] I want to use images of assets! Until you can view the image in Vue.js
[For Rails beginners] Implemented multiple search function without Gem
Ruby on Rails 5 quick learning practice guide that can be used in the field Summary
I made a reply function for the Rails Tutorial extension (Part 4): A function that makes the user unique
[Question] Can nullif be used in the count function in JPQL?
In the login function, processing that prevents others from editing or deleting posts (Rails / for beginners)
I implemented the code to learn multiple images at once in the Watson Visual Recognition Collection in Java.
[Rails] I can post S3 images in my local environment, but I can't switch to S3 on Heroku.
I tried to implement the image preview function with Rails / jQuery
I made a question that can be used for a technical interview
[Ruby on Rails] Posting function that only logged-in users can post
I made a reply function for the Rails Tutorial extension (Part 5):
[Spring Boot] List of validation rules that can be used in the property file for error messages
[Rails] About the error that the image is not displayed in the production environment
[Java] Implement a function that uses a class implemented in the Builder pattern