[RUBY] Register multiple images for one product. I know what you're talking about! !! ~ part3 ~

Premise

--Use ruby on rails 6.0.0. --User functions are assumed to be introduced by devise. --All view files are in haml format. ――By the way, I'm using MacBook Air (Retina, 13-inch, 2020).

Introduction

This is a synopsis of the last time (part2) . We have implemented a function that allows you to post images when registering products using the uploader of carrierwave.

Prefaces and procedures are described in detail in part1 , so if you're curious, click on LGTM Let's press. Nothing in particular happens.

Since it was possible to post only one image last time, this time we will be able to register up to 5 images at once. The third step, "Introduce jQuery and implement multiple image posting", isn't it?

It took 30,000 years to register one image, but if I wanted to register five, it would take another 150,000 years? (Aho)

Aside from that

Post multiple images

The introduction has become long, but it can't be helped even if I'm shy, so let's do it right away.

In the current state, only one image form is displayed, and if you select one, that is the end. That's where javascript comes in. (This time I will use jQuery) Finally, if you enter one image, a new form will appear, and you can register the image up to 5 times, the goal is.

About jQuery

First of all, the introduction of jQuery, but in Rails 6, as far as I know, there are two directions for the introduction of jQuery.

--How to install jQuery as gem --How to call jQuery through webpacker

This time, I did it by the method through the gem mentioned above. I think there are many people who are confused, so I will post the introduction method of jQuery as an extra edition later. Or rather, I was confused.

Let's skip the time

So, let's proceed with the introduction of jQuery safely.

haml:app/views/products/_form.html.haml


= form_with model: @product, local: true do |f|
  = f.text_field :name, placeholder: 'name'
  #image-box
    = f.fields_for :images do |i|
      .group{ data: { index: i.index } }
        = i.file_field :src, class: 'file'
  = f.submit 'SEND'

First, add a class and ID to the form view file. * {data: ~} * is the custom data attribute specification. I don't think there are any other problems. I'm just writing the basics in haml.

app/assets/javascripts/product.js


$(function() {
  const buildFileField = (index)=> {
    const html = `<div data-index="${index}" class="group">
                    <input class="file" type="file"
                    name="product[images_attributes][${index}][src]"
                    id="product_images_attributes_${index}_src"><br>
                    <div class="remove">Delete</div>
                  </div>`;
    return html;
  }
  
  let fileIndex = [1,2,3,4,5];

  $('#image-box').on('change', '.file', function(e) {
    $('#image-box').append(buildFileField(fileIndex[0]));
    fileIndex.shift();
    fileIndex.push(fileIndex[fileIndex.length - 1] + 1)
  });

  $('#image-box').on('click', '.remove', function() {
    $(this).parent().remove();
    if ($('.file').length == 0) $('#image-box').append(buildFileField(fileIndex[0]));
  });
});

Here is the description of jQuery. I will write in detail in the extra edition, but since there is no javascript in the assets folder of Rails 6, you need to create it yourself.

Let's explain step by step.

let fileIndex = [1,2,3,4,5];

$('#image-box').on('change', '.file', function(e) {
  //Create a new form with the first number of fileIndex as the index when a file is selected.
  $('#image-box').append(buildFileField(fileIndex[0]));
  //Delete the first number in fileIndex and shift the numbers one by one to the left.
  fileIndex.shift();
  //Insert the last number of fileIndex plus 1 at the end.
  fileIndex.push(fileIndex[fileIndex.length - 1] + 1)
  });

First of all, when you select an image in the displayed form, a new form will be displayed. It is a process like that. I added the idea line by line. By repeating this, each form can have its own index.

const buildFileField = (index)=> {
    const html = `<div data-index="${index}" class="group">
                    <input class="file" type="file"
                    name="product[images_attributes][${index}][src]"
                    id="product_images_attributes_${index}_src"><br>
                    <div class="remove">Delete</div>
                  </div>`;
    return html;
  }

This is the description of the process of buildFileField. The unique index created earlier is passed as an argument. The part enclosed in `` is just rewriting the form described in _form.html.haml as html and adding id and name so that it can be referred to later.

$('#image-box').on('click', '.remove', function() {
  //Clicked.Remove the parent element of remove.
  $(this).parent().remove();
  //Display a new form when the number of forms reaches 0.
  if ($('.file').length == 0) $('#image-box').append(buildFileField(fileIndex[0]));
});

Finally, it's the process of deleting the form. I also wrote this line by line.

By the way, the processing on the registration screen has been completed for the time being. As long as I knew how to write jQuery, I think it wouldn't have been particularly difficult. Speaking of which, it may have been difficult to tell whether it is a method or a class, such as file or remove, but everything written in the form of'. ~'Is a class. Once you get used to it, you can easily identify it.

Finally

It was an exaggerated introduction, but in fact, multiple registrations in the database itself ended in the last time. So this time, the main work was at the front desk.

It's finally in shape. Now that we have registered multiple images, we would like to edit multiple images in the next part.

See you in the next part.

I want to implement the product information editing function ~ part4 ~

Recommended Posts

Register multiple images for one product. I know what you're talking about! !! ~ part3 ~