[Ruby] Register multiple images for one product. I know what you’re saying! !! ~part3~

4 minute read

Assumption

  • 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 use MacBook Air (Retina, 13-inch, 2020).

Introduction

This is a synopsis of the previous time (part2). Implemented a function that allows you to post an image when registering a product using the carrier wave uploader.

Foreword and procedures are described in detail in part1, so if you are worried, click and think LGTM Let’s press. Nothing happens in particular.

Last time I was able to post only one image, so this time I will be able to register up to 5 images at once. The third step is “implementing posting of multiple images by introducing jQuery”.

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

That aside,

Post multiple images

The introduction has become long, but since there is no way to avoid it, let’s do it at once.

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

About jQuery

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

  • How to install jQuery as a gem
  • How to call jQuery through webpacker

This time, I did it through the above mentioned gem. I think that many people will be 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 the class and ID to the view file of form. { data: ~ } is a custom data attribute specification. Other than that, I don’t think there is a problem. I am 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">Remove</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]));
  });
});

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

Let’s walk through each step.

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

$('#image-box').on('change','.file', function(e) {
  // Create a new form with the first number in fileIndex as the index when the 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 1 at the end of fileIndex and add 1 at the end.
  fileIndex.push(fileIndex[fileIndex.length-1] + 1)
  });

First, here, when you select an image in the displayed form, a new form is displayed. It is such a process. I added a line-by-line way of thinking. By repeating this, each form can have its own unique 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">Remove</div>
                  </div>`;
    return html;
  }

It describes 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 the id and name so that it can be referenced later.

$('#image-box').on('click','.remove', function() (
  // Remove the clicked .remove parent element.
  $(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 is the process of deleting the form. I wrote this line by line as well.

By the way, the processing on the registration screen is completed for now. I think it would have been particularly difficult if you only knew how to write jQuery. Speaking of which, it may be difficult to understand whether it is a method or a class such as file or remove, but all that is described in the form of’.~’ is a class. Once you get used to it, you can easily identify it.

Finally

It was a big introduction, but the fact that multiple registrations to the database itself ended in the last time. So this time the main work was on the front.

It has finally taken shape. Since multiple images can be registered this time, I would like to edit multiple images in the next part.

See you in the next part.

I would like to implement a product information editing function ~part4~