[JAVA] [Rails] Implémentation de la fonction de catégorie d'ascendance gemme

introduction

Mon nom est Kusano. Ce message sera une sortie après avoir examiné ce que j'ai appris à l'école de programmation. Le texte est médiocre car c'est une note pour moi, mais j'espère qu'il aidera autant que possible les débutants. Comme le titre l'indique, le contenu porte sur la mise en œuvre de la fonction de catégorie de l'application Furima par le développement d'équipe mené à l'école. Je pense qu'il y a de nombreux points immatures. Veuillez signaler toute lacune. Je vais l'améliorer de temps en temps.

Produit fini

Lorsque la catégorie parent est sélectionnée, l'événement se déclenche et les cases enfant, petit-enfant et sélection s'affichent.

** Écran d'enregistrement de catégorie lors de la liste des produits ** Image from Gyazo

** Écran d'appel d'informations sur la catégorie pour des informations détaillées sur le produit ** qiita_カテゴリー商品情報.png

Procédure de montage

** 1. Création d'un modèle et définition d'une association dans DB **

--Installation de l'ascendance des gemmes --Création d'un modèle de catégorie --category Création du fichier de migration --Définition d'association avec le modèle d'élément

** 2. Fonction d'enregistrement de catégorie **

** 3. Informations sur la catégorie d'appel **

--Définissez les variables d'instance parent, enfant et petit-enfant dans la méthode show du contrôleur d'éléments --items Décrit dans un fichier haml à l'aide de la variable d'instance définie dans le contrôleur et appelée dans la vue

Création de modèle / définition d'association à DB

Utilisez la gemme «ascendance» de Ruby on Rails pour ajouter des fonctionnalités de catégorie.

Gemfile 


gem 'ancestry'

Créez un modèle de catégorie avec la commande rails g model category dans le terminal. Décrivez has_ancestory.

app/models/category.rb 


class Category < ApplicationRecord
  has_ancestry
  has_many :items
end

Écrivez ce qui suit dans le fichier de migration des catégories et exécutez la commande rails db: migrate dans le terminal.

db/category.rb&nbsp;


class CreateCategories < ActiveRecord::Migration[5.2]
  def change
    create_table :categories do |t|
      t.string :name,     null: false
      t.string :ancestry
      t.timestamps
    end
    add_index :categories, :ancestry
  end
end

Décrivez toutes les catégories sur la feuille de calcul Google. La colonne A est id, la colonne B est le nom (nom de la catégorie) et la colonne C est l'ascendance (valeur numérique qui distingue les parents et les descendants). J'ai écrit toutes les catégories dans un fichier CSV, mais il y avait 1368 lignes, donc j'ai eu du mal à entrer. (Je me souviens du travail de bureau que je faisais dans mon emploi précédent.) Soit dit en passant, il existe une catégorie sans petits-enfants, alors faites attention à ne pas modifier la valeur de l'ascendance. Vous pouvez enregistrer les données en suivant les étapes de Fichier → Télécharger → valeurs séparées par des virgules (feuille actuelle .csv). Image from Gyazo Image from Gyazo Placez le fichier CSV téléchargé directement dans le fichier db. Cursor_と_category_csv_—_freemarket_sample_75a-2.png

Écrivez ce qui suit dans le fichier seeds.rb et exécutez la commande rails db: seed dans le terminal pour lire le fichier CSV et générer automatiquement un enregistrement DB. Bien qu'il s'agisse d'une explication sur le contenu de la description, spécifiez le fichier que vous souhaitez lire après foreach. La description ci-dessous sera le nom du modèle.create (nom de la colonne => colonne que vous souhaitez charger). row [0] → Une colonne est id ligne [1] → la colonne B est le nom (nom de la catégorie) ligne [2] → la colonne C est l'ascendance (valeur numérique qui distingue les parents et les descendants)

db/seeds.rb&nbsp;


require "csv"

CSV.foreach('db/category.csv') do |row|
  Category.create(:id => row[0], :name => row[1], :ancestry => row[2])
end 

Fonction d'enregistrement de catégorie

Paramètres de routage pour JSON dans les catégories enfants et petits-enfants Les deux premiers de la collection sont les routages pour le JSON créé cette fois. En écrivant les valeurs par défaut: {fomat: 'json'}, ce sera pour JSON uniquement.

config/routes.rb&nbsp;


  resources :items do
    resources :comments,  only: [:create, :destroy]
    resources :favorites, only: [:create, :destroy]
    collection do
      get 'get_category_children', defaults: { fomat: 'json'}
      get 'get_category_grandchildren', defaults: { fomat: 'json'}
      get 'search'
      get 'post_done'
      get 'delete_done'
      get 'detail_search'
      get 'update_done'
    end
  end

Définition de variable d'instance de catégorie parente pour le contrôleur d'éléments Définissez la description suivante dans la nouvelle méthode. (Au fur et à mesure que l'implémentation progresse, elle sera également utilisée pour d'autres actions, elle sera donc redéfinie comme privée plus tard et refactorisée avec before_action.)

app/controllers/items_controller.rb&nbsp;


@category_parent_array = Category.where(ancestry: nil)

Éléments Définition de la méthode du contrôleur pour JSON des catégories enfants et petits-enfants La description entre parenthèses de params [] décrit: parent_id et: child_id envoyés par ajax dans le fichier JavaScript expliqué plus loin.

app/controllers/items_controller.rb&nbsp;


  def get_category_children
    @category_children = Category.find("#{params[:parent_id]}").children
  end

  def get_category_grandchildren
    @category_grandchildren = Category.find("#{params[:child_id]}").children
  end

Créez un fichier json.jbuilder et décrivez la conversion en données JSON.

rb:app/views/items/get_category_children.json.jbuilder&nbsp;


json.array! @category_children do |child|
  json.id child.id
  json.name child.name
end

rb:app/views/items/get_category_grandchildren.json.jbuilder&nbsp;


json.array! @category_grandchildren do |grandchild|
  json.id grandchild.id
  json.name grandchild.name
end

Définissez le comportement lors de la sélection d'un parent, d'un enfant ou d'un petit-enfant avec JavaScript

app/assets/javascripts/category.js&nbsp;


$(function(){
  function appendOption(category){
    var html = `<option value="${category.id}">${category.name}</option>`;
    return html;
  }
  function appendChildrenBox(insertHTML){
    var childSelectHtml = "";
    childSelectHtml = `<div class="category__child" id="children_wrapper">
                        <select id="child__category" name="item[category_id]" class="serect_field">
                          <option value="">---</option>
                          ${insertHTML}
                        </select>
                      </div>`;
    $('.append__category').append(childSelectHtml);
  }
  function appendGrandchildrenBox(insertHTML){
    var grandchildSelectHtml = "";
    grandchildSelectHtml = `<div class="category__child" id="grandchildren_wrapper">
                              <select id="grandchild__category" name="item[category_id]" class="serect_field">
                                <option value="">---</option>
                                ${insertHTML}
                                </select>
                            </div>`;
    $('.append__category').append(grandchildSelectHtml);
  }

  $('#item_category_id').on('change',function(){
    var parentId = document.getElementById('item_category_id').value;
    if (parentId != ""){
      $.ajax({
        url: '/items/get_category_children/',
        type: 'GET',
        data: { parent_id: parentId },
        dataType: 'json'
      })
      .done(function(children){
        $('#children_wrapper').remove();
        $('#grandchildren_wrapper').remove();
        var insertHTML = '';
        children.forEach(function(child){
          insertHTML += appendOption(child);
        });
        appendChildrenBox(insertHTML);
      })
      .fail(function(){
        alert('Échec de l'obtention de la catégorie');
      })
    }else{
      $('#children_wrapper').remove();
      $('#grandchildren_wrapper').remove();
    }
  });
  $('.append__category').on('change','#child__category',function(){
    var childId = document.getElementById('child__category').value;
    if(childId != "" && childId != 46 && childId != 74 && childId != 134 && childId != 142 && childId != 147 && childId != 150 && childId != 158){
      $.ajax({
        url: '/items/get_category_grandchildren',
        type: 'GET',
        data: { child_id: childId },
        dataType: 'json'
      })
      .done(function(grandchildren){
        $('#grandchildren_wrapper').remove();
        var insertHTML = '';
        grandchildren.forEach(function(grandchild){
          insertHTML += appendOption(grandchild);
        });
        appendGrandchildrenBox(insertHTML);
      })
      .fail(function(){
        alert('Échec de l'obtention de la catégorie');
      })
    }else{
      $('#grandchildren_wrapper').remove();
    }
  })
});

Je vais expliquer la description ci-dessus. L'événement est défini pour se déclencher lorsqu'une catégorie est sélectionnée dans la zone de sélection parent qui s'affiche en premier dans la description suivante sur la ligne du milieu. La description sur la deuxième ligne obtient l'identifiant de la catégorie sélectionnée et définit les variables.


$('#item_category_id').on('change',function(){
    var parentId = document.getElementById('item_category_id').value;

Ensuite, placez l'id de la catégorie acquise dans ① par ajax dans parent_id, transmettez l'id parent_id au contrôleur via la route pour JSON acheminée plus tôt et acquérez l'enregistrement de la catégorie enfant.


      $.ajax({
        url: '/items/get_category_children/',
        type: 'GET',
        data: { parent_id: parentId },
        dataType: 'json'
      })

Si la communication ajax réussit, l'enregistrement de catégorie enfant acquis dans (2) est développé par la méthode forEach sur la 5ème ligne. La méthode remove sur les 2ème et 3ème lignes est écrite pour supprimer les cases de sélection enfant et petit-enfant lorsqu'une autre catégorie est à nouveau sélectionnée dans la case de sélection parent.


.done(function(children){
        $('#children_wrapper').remove();
        $('#grandchildren_wrapper').remove();
        var insertHTML = '';
        children.forEach(function(child){
          insertHTML += appendOption(child);
        });
        appendChildrenBox(insertHTML);
      })

La fonction appendOption décrite dans la ligne supérieure transmet l'enregistrement enfant acquis précédemment avec l'argument de appendOption (enfant) sur la 6ème ligne de ③, et incorpore respectivement id et nom (nom de catégorie) dans la balise option.


  function appendOption(category){
    var html = `<option value="${category.id}">${category.name}</option>`;
    return html;
  }

Pour appendChildrenBox, le contenu de ④ est placé dans le insertHTML décrit dans la 6ème ligne de ③, et la balise option de ④ est passée comme argument de appendChildrenBox (insertHTML) décrit dans la 8ème ligne de ③. Incorporez la balise option avec la description de \ $ {insertHTML} Enfin, la description de $ ('.append__category'). Append (childSelectHtml); amène le navigateur à afficher la boîte de sélection enfant de manière asynchrone. Le déroulement de la boîte de sélection du petit-fils est le même.


  function appendChildrenBox(insertHTML){
    var childSelectHtml = "";
    childSelectHtml = `<div class="category__child" id="children_wrapper">
                        <select id="child__category" name="item[category_id]" class="serect_field">
                          <option value="">---</option>
                          ${insertHTML}
                        </select>
                      </div>`;
    $('.append__category').append(childSelectHtml);
  }

Si la communication ajax échoue, une alerte sera affichée.


      .fail(function(){
        alert('Échec de l'obtention de la catégorie');
      })

Pour l'instruction if décrite ci-dessus ajax, la valeur initiale est définie sur nil en utilisant l'option include_blank de collection_select dans le fichier haml, et lorsque cela sélectionne l'option avec id à partir de nil, la communication ajax démarre. Au contraire, lorsqu'il est renvoyé à la valeur initiale de "Veuillez sélectionner", il devient else et la boîte de sélection du petit-enfant est supprimée.


 if (parentId != ""){
#La description au milieu est omise
    }else{
      $('#grandchildren_wrapper').remove();

En ce qui concerne la différence entre la description de l'enfant et la description du petit-enfant, la description du petit-enfant doit être décrite comme suit lorsque celle ajoutée par javaScript est ciblée pour le déclenchement d'événement. \ $ (Étendue de l'enquête) .on (nom de l'événement, lieu où l'événement se produit, function () { De plus, le branchement conditionnel est défini de sorte que la communication ajax démarre lorsque l'instruction if n'est pas dans la catégorie sans petits-enfants.


$('.append__category').on('change','#child__category',function(){
    var childId = document.getElementById('child__category').value;
    if(childId != "" && childId != 46 && childId != 74 && childId != 134 && childId != 142 && childId != 147 && childId != 150 && childId != 158){

Il y a une mise en garde lors de l'affichage de la zone de sélection de manière asynchrone sur le navigateur. Il s'agit de la partie où les enfants et les petits-enfants ont "item [category_id]" dans l'option de nom dans la balise select. L'option name spécifie quel category_id du parent, de l'enfant ou du petit-enfant doit être stocké dans la table des éléments.

** Ajouter l'option de nom uniquement aux enfants et entrer dans la catégorie des petits-enfants ** → Dans DB, l'ID enfant est enregistré ** Ajouter l'option de nom uniquement aux petits-enfants, entrez la catégorie sans petits-enfants ** → Dans DB, l'id category_id parent est sauvegardé ** Ajouter une option de nom pour les enfants et petits-enfants, et entrer jusqu'à la catégorie petits-enfants ** → Dans DB, la variable de sélection avec l'option de nom affichée de manière asynchrone à la fin est enregistrée avec priorité.

La raison pour laquelle il est nécessaire de sauvegarder le category_id du petit-enfant est que les enregistrements parent et enfant peuvent être appelés en fonction du category_id du petit-enfant lors de l'appel des informations de catégorie.


  function appendChildrenBox(insertHTML){
    var childSelectHtml = "";
    childSelectHtml = `<div class="category__child" id="children_wrapper">
                        <select id="child__category" name="item[category_id]" class="serect_field">
                          <option value="">---</option>
                          ${insertHTML}
                        </select>
                      </div>`;
    $('.append__category').append(childSelectHtml);
  }
  function appendGrandchildrenBox(insertHTML){
    var grandchildSelectHtml = "";
    grandchildSelectHtml = `<div class="category__child" id="grandchildren_wrapper">
                              <select id="grandchild__category" name="item[category_id]" class="serect_field">
                                <option value="">---</option>
                                ${insertHTML}
                                </select>
                            </div>`;
    $('.append__category').append(grandchildSelectHtml);
  }

Affichez la boîte de sélection parent dans le fichier haml.

rb:app/views/items/_form.html.haml&nbsp;


    .append__category
      .category
        .form__label
          .lavel__name 
Catégorie
          .lavel__Required
            [Obligatoire]
        =f.collection_select :category_id, @category_parent_array, :id, :name,{ include_blank: "Veuillez sélectionner"},class:"serect_field"

Informations sur la catégorie d'appel

Définissez les variables d'instance parent, enfant et petit-enfant dans la méthode show du contrôleur d'éléments

app/controllers/items_controller.rb&nbsp;


@category_id = @item.category_id
@category_parent = Category.find(@category_id).parent.parent
@category_child = Category.find(@category_id).parent
@category_grandchild = Category.find(@category_id)

Appelez la catégorie enregistrée à l'aide de la variable d'instance définie précédemment dans le contrôleur d'éléments à la vue avec un fichier haml. L'instruction if est conditionnelle à l'affichage sans petits-enfants ou avec petits-enfants. (Puisque le chemin n'est pas spécifié pour le lien cette fois, il est défini sur #.)

rb:app/views/items/_main_show.html.haml&nbsp;


            %table 
              %tr 
                %e vendeur
                %td= @user.nickname
              %tr 
                %catégorie
                - if [46, 74, 134, 142, 147, 150, 158].include?(@category_id)
                  %td
                    = link_to "#{@category_child.name}","#"
                    %br= link_to "#{@category_grandchild.name}","#" 
                -else
                  %td
                    = link_to "#{@category_parent.name}","#"
                    %br= link_to "#{@category_child.name}","#"
                    = link_to "#{@category_grandchild.name}","#"
              %tr
                %e marque
                %td= @item.brand_name
              %tr
                %taille du produit
                %td
              %tr
                %Statut du produit
                %td= @item.item_status
              %tr
                %e Frais d'expédition
                %td= @item.delivery_fee
              %tr
                %e Zone d'expédition
                %td= link_to "#{@item.shipping_origin}","#"
              %tr
                %Date d'expédition estimée
                %td= @item.days_until_shipping

Articles que j'ai utilisés comme référence

Réalisez une boîte de sélection de catégorie dynamique en utilisant des données multicouches par ascendance ~ Ajax ~ [Français] Gem Ancestry Official Document

Recommended Posts

[Rails] Implémentation de la fonction de catégorie d'ascendance gemme
[Rails] Implémentation de la fonction de catégorie
[Rails] Implémentation de la fonction de catégorie multicouche en utilisant l'ascendance "Préparation"
[Rails] Fonction de catégorie
[Rails] Implémentation de la fonction de catégorie multicouche à l'aide de l'ascendance "seed edition"
[Rails] Implémentation de la fonction de catégorie multicouche en utilisant l'ascendance "Edit Form Edition"
[Rails] Implémentation de la fonction de catégorie multicouche à l'aide de l'ascendance "Formulaire de création"
Implémentation de la fonction de recherche floue Rails
Mise en œuvre de la fonction déroulante de catégorie
[Rails] Implémentation de la fonction tutoriel
[Rails] Implémentation d'une fonction similaire
[Rails] Implémentation de la fonction d'importation CSV
[Rails] Implémentation de la fonction de prévisualisation d'image
[Rails] À propos de la mise en œuvre de la fonction similaire
[Rails] Implémentation de la fonction de retrait utilisateur
[Rails] Implémentation de la fonction d'exportation CSV
[Rails] Implémentation de fonctions de catégorie plusieurs à plusieurs
[Ruby on Rails] Implémentation de la fonction de commentaire
[Rails] Commentaire mémo de procédure d'implémentation
[Ruby on Rails] Suivez l'implémentation de la fonction: bidirectionnelle
Rails [Pour les débutants] Implémentation de la fonction de commentaire
Échafaudage de procédure d'implémentation de fonction CRUD de base
[Ruby on rails] Implémentation d'une fonction similaire
[Rails] Implémentation de la fonction de catégorie multicouche en utilisant l'ascendance "J'ai essayé de créer une fenêtre avec Bootstrap 3"
Implémentation de la fonction DM
Les rails suivent la fonction
[Rails] Fonction de notification
Implémentation de la fonction de connexion Ruby on Rails (Session)
[Rails] Implémentation de la fonction d'agrandissement d'image à l'aide de lightbox2
Mettre en œuvre la fonction de catégorie de produit en utilisant l'ascendance ① (Préparation)
Ruby on Rails Implémentation de la fonction d'envoi automatique de courrier
Implémentation de la recherche par hashtag Rails
Implémentation du compte à rebours Rails6
[rails] gem'payjp'implementation procedure
Implémentation de la fonction de connexion Ruby on Rails (édition de devise)
Implémentation de la fonction Rails CRUD ② (édité et détaillé cette fois)
Implémentation de la fonction de commentaire (Ajax)
Implémentation de Rails Action Text
Suivez l'implémentation de la fonction (Ajax)
Implémentation de la fonction de recherche
[Pour les débutants de Rails] Implémentation de la fonction de recherche multiple sans Gem
Implémentation de la fonction de prévisualisation d'image
Mise en œuvre de la fonction de pagénation
Fonction de recherche [implémentation copier-coller]