[RUBY] Méthode de mise en œuvre consistant à lier plusieurs images à un article et à publier en même temps

introduction

J'ai posté un article sous forme de mémorandum indiquant que j'avais du mal à implémenter la fonction de publication de plusieurs images

Lancez l'appli

$ rails _5.2.3_nouveau nom d'application-d mysql
$nom de l'application cd
$ bin/rails db:create

Introduction de haml

Puisque cette implémentation se fera avec haml, nous allons introduire haml

Ajoutez ce qui suit au fichier gem N'oubliez pas de faire l'installation du bundle

gem 'haml-rails'

Créez facilement une fonction de publication

routes


Rails.application.routes.draw do
  root 'products#index'
  resources :products, only: [:index, :new, :create]
end

controller


class ProductsController < ApplicationController
  def index
    @products = Product.includes(:images).order('created_at DESC')
  end

  def new
    @product = Product.new
    @product.images.new
  end

  def create
    @product = Product.new(product_params)
    if @product.save
      redirect_to root_path
    else
      render :new
    end
  end
  

  private

  def product_params
    params.require(:product).permit(:name, images_attributes: [:src])
  end

end

modèle et migration

fichier de migration de produit

class CreateProducts < ActiveRecord::Migration[5.2]
  def change
    create_table :products do |t|
      t.string :name

      t.timestamps
    end
  end
end

fichier de migration d'image


 class CreateImages < ActiveRecord::Migration[5.2]
  def change
    create_table :images do |t|
      t.string :src
      t.references :product, foreign_key: true

      t.timestamps
    end
  end
end

modèle de produits


class Product < ApplicationRecord
  has_many :images
  accepts_nested_attributes_for :images, allow_destroy: true
end

modèle d'image


class Image < ApplicationRecord
  mount_uploader :src, ImageUploader
  belongs_to :product
end

Nous pourrons télécharger des images avec le modèle d'image.

Ajoutez ce qui suit à l'installation Gemfile et $ bundle

gem 'carrierwave'
gem 'mini_magick'

Créer un uploader

Procédez comme suit dans le terminal

$ rails g uploader image

Ensuite, le fichier image_uploader.rb a été généré, alors modifiez ce qui suit

include CarrierWave::MiniMagick  //Trouvez cette description et décommentez

process resize_to_fit: [100, 100]  //Cette description est ajoutée

Enfin éditez haml et scss

haml/new



.lead
  =link_to "/products" do
    =image_tag "http://furima.tokyo/assets/logo-d3d78326971d78b06e3d6f0ba666d025a8ad681286b4d9e00e7dbe8673bcfd23.svg", class: "lead__img"
  
= form_with model: @product, local: true do |f|
  .input-field
    .input-field__contents
      .input-field__contents-image
        .input-field__contents-image__headline
          .headlabel
Image de l'exposition
            %span.necessary
Obligatoire
        %p.upload
Vous pouvez télécharger jusqu'à 5 photos
        
        #image-box-1 
          .item-num-0#image-box__container
            = f.fields_for :images do |i|
              .input-field__contents-image__drop__js-file
                .input-area
                  = i.file_field :src
    
      .input-field__contents-name
        .input-field__contents-image__headline
          .headlabel
            %label
Nom du produit
              %span.necessary
Obligatoire
          .name-input
            = f.text_field :name, {class: "drop-input", placeholder: "Jusqu'à 40 caractères"}
    
    .input-field
      .input-field__contents
        .input-field__contents-price
          .sell
            = f.submit "Vendre", class: "sellbtn", tabindex: "0"

new.scss



.lead {
  background-color: rgb(245, 245, 245);
  text-align: center;
  height: 128px;
  line-height: 10;
}
.input-field {
  background-color: rgb(245, 245, 245);
  width: 100%;
  .input-field__contents {
    left: 0;
    background-color: white;
    max-width: 800px;
    margin: 0 auto;
    padding: 40px;
    border-bottom: 1px solid hsl(0, 0%, 77%);
    height: 100%;
    .input-field__contents-image {
      width: 800px;
      border-bottom: rgb(204, 204, 204);
      .input-field__contents-image__headline{
        margin-top: 20px;
        margin-left: 5px;
      }
      .upload {
        margin-top: 16px;
        margin-left: 5px;
      }
      #image-box-1 {
        display: flex;
        height: 130px;
        width: 100%;
        margin-right: 0px;
        text-align: center;
        i{
          padding-top: 50px;     
        }
        .item-num-0#image-box__container  {
        background-color: rgb(245, 245, 245);
        height: 100%;
        width: 100%;
        border-width: 1px;
        border-style: dashed;
        border-color: rgb(204, 204, 204);
        border-image: initial;
        text-align: center;
        }
      }
    }
  }
  .drop-input {
    width: 60%;
    height: 50px;
    border-color: #cccccc;
    border-radius: 4px;
    border-style: solid;
    border-width: 1px;
    margin: 10px 10px 0 0;
  }  
  .name-input{
    .drop-input{
      width: 100%;
      height: 50px;
      border-color: #cccccc;
      border-style: solid;
    }
  } 
  .sell {
    text-align: center;
    display: grid;
    width: 50%;
    margin-left: 200px;
    .sellbtn {
      background-color: #3ccace;
      color: white;
      border-color: transparent;
      font-weight: 600;
      line-height: 3;
      cursor: pointer;
    }
  }
}

S'il ressemble à ce qui suit, il est complet. https://gyazo.com/a1d705516656f50c689abc7c18de5ec9

Publier plusieurs images

Introduction de jQuery

gem 'jquery-rails'

Ensuite, effectuez l'installation groupée

Modification de application.js

//= require rails-ujs
//= require activestorage
//= require jquery
//= require_tree .

Modification de new.haml


-#Avant de modifier
#image-box-1 
 .item-num-0#image-box__container
  = f.fields_for :images do |i|
   .input-field__contents-image__drop__js-file
    .input-area
     = i.file_field :src
-#Après l'édition

#image-box-1 
 .item-num-0#image-box__container
  = f.fields_for :images do |i|
   .input-field__contents-image__drop__js-file
    .input-area
    = i.file_field :src, type: 'file', name: "product[images_attributes][][name]", value:"", style: "display:none", id:"img-file"
    %label{for: "img-file"}
     %i.fas.fa-camera

Créez et modifiez new.js pour publier plusieurs images

new.js


$(function(){
  //Créer une boîte pour stocker des données avec un objet DataTransfer
  var dataBox = new DataTransfer(); //Étape ②
  //fichier avec querySelector_obtenir le champ
  var file_field = document.querySelector('input[type=file]')
  //Événement qui se déclenche lorsque le fichier est sélectionné
  $('#img-file').change(function(){
    //Récupère l'objet du fichier sélectionné avec prop
    var files = $('input[type=file]').prop('files')[0];
    $.each(this.files, function(i,file){
    //Lire l'objet File spécifié par readAsDataURL de FileReader
    var fileReader = new FileReader();

    //Ajouter un fichier à l'objet DataTransfer
    dataBox.items.add(file) //Étape ②
    //liste de fichiers de fichiers dans l'objet dataTransfer_Remplaçant sur le terrain
    file_field.files =  dataBox.files //Étape ②

    var num = $('.item-image').length + 1 + i //Étape ②
    fileReader.readAsDataURL(file); //Étape ②
     //Lorsque le nombre d'images atteint 10, supprimez la boîte de dépôt lorsqu'elle dépasse
     if (num == 5){ //Étape ②
      $('#image-box__container').css('display', 'none')
     }
    //Lorsque le chargement est terminé, stockez l'URL du fichier dans src
    fileReader.onloadend = function() {
      var src = fileReader.result
      var html = `<div class='item-image' data-image="${file.name}">
                    <div class=' item-image__content'>
                      <div class='item-image__content--icon'>
                        <img src=${src} width="150" height="90" >
                      </div>
                    </div>
                    <div class='item-image__operetion'>
                      <div class='item-image__operetion--delete'>Effacer</div>
                    </div>
                  </div>`
     //image_box__Insérer html avant l'élément conteneur
      $('#image-box__container').before(html);
      };
    //   fileReader.readAsDataURL(file);
    //  });
     //image-box__Changez la classe du conteneur et changez la taille de la boîte de dépôt avec CSS.
     $('#image-box__container').attr('class', `item-num-${num}`)
    });
  });
    $(document).on("click", '.item-image__operetion--delete', function(){
      //Obtenir un élément d'aperçu
      var target_image = $(this).parent().parent()
      //Supprimer l'aperçu
      target_image.remove();
      //Supprimer le fichier dans la balise d'entrée
      file_field.val("")
    })
});

Modification de scss


.lead {
  background-color: rgb(245, 245, 245);
  text-align: center;
  height: 128px;
  line-height: 10;
}

.input-field {
  background-color: rgb(245, 245, 245);
  width: 100%;
  &__contents {
    left: 0;
    background-color: white;
    max-width: 800px;
    margin: 0 auto;
    padding: 40px;
    border-bottom: 1px solid hsl(0, 0%, 77%);
    height: 100%;
  }
  
  .input-field__contents-image {
    width: 800px;
    border-bottom: rgb(204, 204, 204);
    .input-field__contents-image__headline{
      font-weight: 600;
      margin-top: 20px;
      margin-left: 5px;
      .name-input {
        height: 54px;
        .option-input {
          display: block;
          width: 93%;
          border-color: #cccccc;
          height: 100%;
          border-radius: 4px;
          font-weight: bolder;
          padding: 0px 2px 1px;
          border-width: 1px;
        }
      }
    }
    .upload {
      margin-top: 16px;
      margin-left: 5px;
    }
    #image-box-1 {
      display: flex;
      height: 130px;
      width: 100%;
      margin-right: 0px;
      text-align: center;
      i{
        padding-top: 50px;
        cursor: pointer;
      }
      .item-num-0#image-box__container  {
      background-color: rgb(245, 245, 245);
      height: 100%;
      width: 100%;
      border-width: 1px;
      border-style: dashed;
      border-color: rgb(204, 204, 204);
      border-image: initial;
      text-align: center;
      }
      .item-num-1{
        background-color: rgb(245, 245, 245);
      height: 100%;
      width: 100%;
      border-width: 1px;
      border-style: dashed;
      border-color: rgb(204, 204, 204);
      border-image: initial;
      text-align: center;
      }
      .item-num-2{
        background-color: rgb(245, 245, 245);
        height: 100%;
        width: 100%;
        border-width: 1px;
        border-style: dashed;
        border-color: rgb(204, 204, 204);
        border-image: initial;
        text-align: center;
      }
      .item-num-3{
        background-color: rgb(245, 245, 245);
        height: 100%;
        width: 100%;
        border-width: 1px;
        border-style: dashed;
        border-color: rgb(204, 204, 204);
        border-image: initial;
        text-align: center;
      }
      .item-num-4{
        background-color: rgb(245, 245, 245);
      height: 100%;
      width: 100%;
      border-width: 1px;
      border-style: dashed;
      border-color: rgb(204, 204, 204);
      border-image: initial;
      text-align: center;

      }
      .item-num-5{
        background-color: rgb(245, 245, 245);
        height: 100%;
        width: 100%;
        border-width: 1px;
        border-style: dashed;
        border-color: rgb(204, 204, 204);
        border-image: initial;
        text-align: center;
      }  
    }
    //Revoir le CSS d'affichage
    .item-image{
      height: 130px;
      width: 160px;
      border: 1px solid #eee;
      margin-right: 10px;
      .item-image__content{
        padding-top: 10px;
        .item-image__content--icon{
        }
      }
      .item-image__operetion{
        .item-image__operetion--delete{
          color: #00b0ff;
          cursor: pointer;
          padding-top: 5px;
         text-align: center;

        }
      }
    }
  }

  .text-area {
    border-radius: 4px;
    font-size: 16px;
    padding: 13px 16px;
    border-color: #cccccc;
    margin-top: 30px;
    
  }
  .drop-input {
    width: 100%;
    height: 50px;
    border-color: #cccccc;
    border-radius: 4px;
    border-style: solid;
    border-width: 1px;
    margin: 10px 10px 0 0;
    ::placeholder {
      padding: 20px;
      font-weight: inherit;
    } 
  }
 
  .headlabel {
    margin-top: 30px;
    .necessary {
      background-color: #3ccace;
      color: white;
      padding: 2px 4px;
      font-size: 14px;
      margin-left: 3px;
      cursor: pointer;
      border-radius: 2px;
     }
  }
  .sell {
    text-align: center;
    display: grid;
    width: 50%;
    margin-left: 200px;
    .sellbtn {
      background-color: #3ccace;
      color: white;
      font-size: 20px;
      min-height: 48px;
      padding: 0 24px;
      border-color: transparent;
      border-radius: 2px;
      font-weight: 600;
      line-height: 3;
    }
  }
}

Ceci complète l'ensemble du processus Vérifiez le fonctionnement https://gyazo.com/372657130a2696e1865c02fdd6e9e303

Les fonctions d'édition et de suppression seront poursuivies dans un article séparé

Recommended Posts

Méthode de mise en œuvre consistant à lier plusieurs images à un article et à publier en même temps
[Java] Erreur d'appel de méthode lorsque l'héritage et l'implémentation de l'interface sont effectués en même temps
[Spring Boot] Publiez des fichiers et d'autres données en même temps [Axios]
[Enregistrer plusieurs photos] Enregistrer plusieurs images de rails en même temps Technique de puissance primitive
[Spring Boot] Tableau / liste de fichiers POST et autres données en même temps [Axios]
Méthode pour additionner le nombre d'années et obtenir la fin du mois
Comment appeler plusieurs noms à la fois dans la même catégorie
Dessinez un graphique à barres et un graphique linéaire en même temps avec MPAndroidChart
Comment modifier le nombre maximum et maximum de données POST dans Spark
Je veux passer l'argument d'Annotation et l'argument de la méthode d'appel à aspect
Sélectionnez le premier non vide parmi plusieurs facultatifs et appelez sa méthode
J'ai essayé de traduire la grammaire de R et Java [Mis à jour de temps en temps]
Comment mettre en œuvre la fonction d'authentification du courrier au moment de l'inscription de l'utilisateur
[Rails] Comment résoudre le décalage temporel de created_at après la méthode de sauvegarde
[Java] Est-il inutile de vérifier "l'identité" dans l'implémentation de la méthode equals ()?
[Ruby] Définissez la hiérarchie en même temps que l'initialisation de Hash avec la méthode tap
Définir l'heure de LocalDateTime à une heure spécifique
Sortie de la façon d'utiliser la méthode slice
Résumé du réglage de l'heure au Japon et de la méthode d'affichage
Comment supprimer le tweet associé à l'utilisateur lorsque vous le supprimez en même temps
Comment écrire un exemple d'implémentation F04 ruby et C99 en temps réel hors ligne
Comportement remarqué lors de l'ajout de RadioButton et de la vérification initiale en même temps dans le code