[JAVA] [Rails] Fonction de catégorie

introduction

Dans le développement de l'application, j'ai ajouté une fonction de catégorie en utilisant un joyau appelé ascendance, donc je l'ai résumé.

table des matières

  1. Sélectionnez / enregistrez la catégorie
  2. Affichage de la recherche par catégorie
  3. Affichage des résultats de la recherche par catégorie

1. Sélectionnez / enregistrez la catégorie

カテゴリー選択・保存

Créer un tableau de catégories

Installez l'ascendance.

gemfile


gem 'ancestry'

Ensuite, créez un modèle de catégorie.

Terminal
rails g model category

Décrivez has_ancestry.

app/models/category.rb


class Category < ApplicationRecord
  has_many :posts
  has_ancestry
end

Décrivez-le dans le fichier de migration comme suit. Pour l'index, cliquez ici (https://qiita.com/seiya1121/items/fb074d727c6f40a55f22)

db/migrate/20XXXXXXXXXXXX_create_categories.rb


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

Je décrirai la catégorie dans 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). Vous pouvez enregistrer les données en suivant les étapes de Fichier → Télécharger → valeurs séparées par des virgules (feuille courante .csv).

カテゴリー記述例 カテゴリー記述例

Placez le fichier csv téléchargé dans le dossier db.

Décrivez comme suit dans le fichier seeds.rb.

db/seeds.rb 


require "csv"

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

Lorsque vous exécutez la commande rails db: seed dans le terminal, le fichier csv est lu et l'enregistrement DB est automatiquement généré. Après foreach, spécifiez le fichier que vous souhaitez lire. 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 (un nombre qui distingue les parents et les descendants)

routage

Définissez le routage des catégories enfants et petits-enfants au format json.

config/routes.rb


Rails.application.routes.draw do
  ~Abréviation~
  resources :posts do
    collection do
      get 'top'
      get 'get_category_children', defaults: { format: 'json' }
      get 'get_category_grandchildren', defaults: { format: 'json' }
      get 'name_search'
    end
  ~Abréviation~
end

manette

Définissez une catégorie parente pour le contrôleur de messages. Comme il est utilisé à plusieurs endroits, il est défini à l'aide de before_action.

app/controllers/posts_controller.rb


def set_parents
  @parents = Category.where(ancestry: nil)
end

Définissez des méthodes pour les catégories enfants et petits-enfants dans le contrôleur de messages.

app/controllers/posts_controller.rb


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 convertissez-le en données json.

ruby:app/views/posts/get_category_children.json.jbuilder 


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

ruby:app/views/posts/get_category_grandchildren.json.jbuilder 


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

Vue

Définissez le comportement lors de la sélection d'une catégorie avec javascript.

:app/javascript/category_post.js
$(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="post[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="post[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: '/posts/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);
        if (insertHTML == "") {
          $('#children_wrapper').remove();
        }
      })
      .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 != ""){
      $.ajax({
        url: '/posts/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);
        if (insertHTML == "") {
          $('#grandchildren_wrapper').remove();
        }
      })
      .fail(function(){
        alert('Échec de l'obtention de la catégorie');
      })
    }else{
      $('#grandchildren_wrapper').remove();
    }
  })
});

Affichez la boîte de sélection de catégorie sur la nouvelle page de publication.

ruby:app/views/posts/new.html.erb


<div class="append__category">
  <div class="category">
    <div class="form__label">
      <div class="weight-bold-text lavel__name ">
Catégorie
      </div>
      <div class="lavel__Required">
        <%= f.collection_select :category_id, @parents, :id, :name,{ include_blank: "Veuillez sélectionner"},class:"serect_field", id:"item_category_id" %>
      </div>
    </div>
  </div>
</div>

2. Affichage de la recherche par catégorie

カテゴリー検索表示

manette

app/controllers/posts_controller.rb


def top
  respond_to do |format|
    format.html
    format.json do
      if params[:parent_id]
        @childrens = Category.find(params[:parent_id]).children
      elsif params[:children_id]
        @grandChilds = Category.find(params[:children_id]).children
      elsif params[:gcchildren_id]
        @parents = Category.where(id: params[:gcchildren_id])
      end
    end
  end
end

Vue

En javascript, nous obtenons la catégorie enfant et la catégorie petit-enfant qui appartiennent à la catégorie parent sur laquelle se trouve la souris.

:app/javascript/category.js
$(document).ready(function () {
  //Afficher la catégorie parent
  $('#categoBtn').hover(function (e) {
    e.preventDefault();
    e.stopPropagation();
    $('#tree_menu').show();
    $('.categoryTree').show();
  }, function () {
    //Je n'ose rien écrire
  });

  //Afficher les catégories d'en-tête de manière asynchrone
  function childBuild(children) {
    let child_category = `
                        <li class="category_child">
                          <a href="/posts/${children.id}/search"><input class="child_btn" type="button" value="${children.name}" name= "${children.id}">
                          </a>
                        </li>
                        `
    return child_category;
  }

  function gcBuild(children) {
    let gc_category = `
                        <li class="category_grandchild">
                          <a href="/posts/${children.id}/search"><input class="gc_btn" type="button" value="${children.name}" name= "${children.id}">
                          </a>
                        </li>
                        `
    return gc_category;
  }

  //Afficher la catégorie parent
  $('#categoBtn').hover(function (e) {
    e.preventDefault();
    e.stopPropagation();
    timeOut = setTimeout(function () {
      $('#tree_menu').show();
      $('.categoryTree').show();
    }, 500)
  }, function () {
    clearTimeout(timeOut)
  });

  //Afficher les catégories enfants
  $('.parent_btn').hover(function () {
    $('.parent_btn').css('color', '');
    $('.parent_btn').css('background-color', '');
    let categoryParent = $(this).attr('name');
    timeParent = setTimeout(function () {
      $.ajax({
          url: '/posts/top',
          type: 'GET',
          data: {
            parent_id: categoryParent
          },
          dataType: 'json'
        })
        .done(function (data) {
          $(".categoryTree-grandchild").hide();
          $(".category_child").remove();
          $(".category_grandchild").remove();
          $('.categoryTree-child').show();
          data.forEach(function (child) {
            let child_html = childBuild(child)
            $(".categoryTree-child").append(child_html);
          });
          $('#tree_menu').css('max-height', '490px');
        })
        .fail(function () {
          alert("Veuillez sélectionner une catégorie");
        });
    }, 400)
  }, function () {
    clearTimeout(timeParent);
  });

  //Afficher la catégorie des petits-enfants
  $(document).on({
    mouseenter: function () {
      $('.child_btn').css('color', '');
      $('.child_btn').css('background-color', '');
      let categoryChild = $(this).attr('name');
      timeChild = setTimeout(function () {
        $.ajax({
            url: '/posts/top',
            type: 'GET',
            data: {
              children_id: categoryChild
            },
            dataType: 'json'
          })
          .done(function (gc_data) {
            $(".category_grandchild").remove();
            $('.categoryTree-grandchild').show();
            gc_data.forEach(function (gc) {
              let gc_html = gcBuild(gc)
              $(".categoryTree-grandchild").append(gc_html);
              let parcol = $('.categoryTree').find(`input[name="${gc.root}"]`);
              $(parcol).css('color', 'white');
              $(parcol).css('background-color', '#b1e9eb');
            });
            $('#tree_menu').css('max-height', '490px');
          })
          .fail(function () {
            alert("Veuillez sélectionner une catégorie");
          });
      }, 400)
    },
    mouseleave: function () {
      clearTimeout(timeChild);
    }
  }, '.child_btn');

  //Lors de la sélection d'une catégorie de petits-enfants
  $(document).on({
    mouseenter: function () {
      let categoryGc = $(this).attr('name');
      timeGc = setTimeout(function () {
        $.ajax({
            url: '/posts/top',
            type: 'GET',
            data: {
              gcchildren_id: categoryGc
            },
            dataType: 'json'
          })
          .done(function (gc_result) {
            let childcol = $('.categoryTree-child').find(`input[name="${gc_result[0].parent}"]`);
            $(childcol).css('color', 'white');
            $(childcol).css('background-color', '#b1e9eb');
            $('#tree_menu').css('max-height', '490px');
          })
          .fail(function () {
            alert("Veuillez sélectionner une catégorie");
          });
      }, 400)
    },
    mouseleave: function () {
      clearTimeout(timeGc);
    }
  }, '.gc_btn');


  //Boutons de la page de liste des catégories
  $('#all_btn').hover(function (e) {
    e.preventDefault();
    e.stopPropagation();
    $(".categoryTree-grandchild").hide();
    $(".categoryTree-child").hide();
    $(".category_grandchild").remove();
    $(".category_child").remove();
  }, function () {
    //En n'écrivant rien, seule l'action qui s'écarte de l'élément parent est propagée.
  });

  //Masquer la catégorie(0 du menu des catégories.Il disparaît lorsque le curseur est supprimé pendant 8 secondes ou plus)
  $(document).on({
    mouseleave: function (e) {
      e.stopPropagation();
      e.preventDefault();
      timeChosed = setTimeout(function () {
        $(".categoryTree-grandchild").hide();
        $(".categoryTree-child").hide();
        $(".categoryTree").hide();
        $(this).hide();
        $('.parent_btn').css('color', '');
        $('.parent_btn').css('background-color', '');
        $(".category_child").remove();
        $(".category_grandchild").remove();
      }, 800);
    },
    mouseenter: function () {
      timeChosed = setTimeout(function () {
        $(".categoryTree-grandchild").hide();
        $(".categoryTree-child").hide();
        $(".categoryTree").hide();
        $(this).hide();
        $('.parent_btn').css('color', '');
        $('.parent_btn').css('background-color', '');
        $(".category_child").remove();
        $(".category_grandchild").remove();
      }, 800);
      clearTimeout(timeChosed);
    }
  }, '#tree_menu');

  //Traitement des boutons de catégorie
  $(document).on({
    mouseenter: function (e) {
      e.stopPropagation();
      e.preventDefault();
      timeOpened = setTimeout(function () {
        $('#tree_menu').show();
        $('.categoryTree').show();
      }, 500);
    },
    mouseleave: function (e) {
      e.stopPropagation();
      e.preventDefault();
      clearTimeout(timeOpened);
      $(".categoryTree-grandchild").hide();
      $(".categoryTree-child").hide();
      $(".categoryTree").hide();
      $("#tree_menu").hide();
      $(".category_child").remove();
      $(".category_grandchild").remove();
    }
  }, '.header__headerInner__nav__listsLeft__item');
});

Définissez la fenêtre de sélection de catégorie sur l'écran supérieur.

ruby:app/views/posts/top.html.erb


  <div class="item-categories">
    <h2>
Liste des catégories
    </h2>
    <%= link_to  posts_path, class: "category-button", id: 'categoBtn' do %>
Recherche par catégorie
    <% end %>
    <div id="tree_menu">
      <ul class="categoryTree">
        <% @parents.each do |parent| %>
          <li class="category_parent">
            <%= link_to search_post_path(parent) do %>
              <input type="button" value="<%= parent.name %>" name="<%= parent.id %>" class="parent_btn">
            <% end %>
          </li>
        <% end %>
      </ul>
      <ul class="categoryTree-child">
      </ul>
      <ul class="categoryTree-grandchild">
      </ul>
    </div>
  </div>

3. Affichage des résultats de la recherche par catégorie

カテゴリいー検索結果表示

routage

Une action de recherche est définie à l'aide de membre pour distinguer les catégories par identifiant.

config/routes.rb


resources :posts do
    ~Abréviation~
    member do
      get 'search'
    end
   ~Abréviation~
end

manette

La catégorie sur laquelle vous avez cliqué est conditionnelle selon qu'il s'agit d'une catégorie parente, d'une catégorie enfant ou d'une catégorie petit-enfant.

app/controllers/posts_controller.rb


  def search
    @category = Category.find_by(id: params[:id])

    if @category.ancestry == nil
      category = Category.find_by(id: params[:id]).indirect_ids
      if category.empty?
        @posts = Post.where(category_id: @category.id).order(created_at: :desc)
      else
        @posts = []
        find_item(category)
      end

    elsif @category.ancestry.include?("/")
      @posts = Post.where(category_id: params[:id]).order(created_at: :desc)

    else
      category = Category.find_by(id: params[:id]).child_ids
      @posts = []
      find_item(category)
    end
  end

  def find_item(category)
    category.each do |id|
      post_array = Post.where(category_id: id).order(created_at: :desc)
      if post_array.present?
        post_array.each do |post|
          if post.present?
            @posts.push(post)
          end
        end
      end
    end
  end

Vue

ruby:app/views/posts/search.html.erb


  <div class="item-categories">
    <h2>
Liste des catégories
    </h2>
    <%= link_to  posts_path, class: "category-button", id: 'categoBtn' do %>
Recherche par catégorie
    <% end %>
    <div id="tree_menu">
      <ul class="categoryTree">
        <% @parents.each do |parent| %>
          <li class="category_parent">
            <%= link_to search_post_path(parent) do %>
              <input type="button" value="<%= parent.name %>" name="<%= parent.id %>" class="parent_btn">
            <% end %>
          </li>
        <% end %>
      </ul>
      <ul class="categoryTree-child">
      </ul>
      <ul class="categoryTree-grandchild">
      </ul>
    </div>
  </div>

Lien de référence

https://qiita.com/k_suke_ja/items/aee192b5174402b6e8ca https://qiita.com/Sobue-Yuki/items/9c1b05a66ce6020ff8c1
https://qiita.com/dr_tensyo/items/88e8ddf0f5ce37040dc8 https://qiita.com/ATORA1992/items/bd824f5097caeee09678 https://qiita.com/misioro_missie/items/175af1f1678e76e59dea https://qiita.com/Rubyist_SOTA/items/49383aa7f60c42141871

Recommended Posts

[Rails] Fonction de catégorie
[Rails] Implémentation de la fonction de catégorie
Les rails suivent la fonction
[Rails] Implémentation de la fonction de catégorie d'ascendance gemme
[Rails] Fonction de notification
[rails] fonction de classement des balises
Implémenter la fonction d'application dans Rails
Implémentation de la fonction de recherche floue Rails
[Rails] Implémenter la fonction de recherche d'utilisateurs
Fonction de recherche à l'aide de [rails] ransack
[Rails] Implémentation de la fonction de catégorie multicouche en utilisant l'ascendance "Préparation"
[Rails] Implémentation de la fonction de catégorie multicouche à l'aide de l'ascendance "seed edition"
Rails ~ Comprendre la fonction de message ~
Mise en œuvre de la fonction déroulante de catégorie
Implémenter la fonction de catégorie en utilisant l'ancêtre
[Rails] Fonction de panier de site EC
[Rails] Implémentation de la fonction tutoriel
[Rails] Implémenter la fonction de publication d'images
[Rails] Implémentation d'une fonction similaire
[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"
[Rails] Implémentation de la fonction d'importation CSV
[Rails] Implémentation asynchrone de la fonction similaire
[Ruby on Rails] Introduction de la fonction de pagination
[Rails] Implémentation de la fonction de prévisualisation d'image
[Rails] Fonction de gestion des balises (en utilisant des actes comme des balises)
[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
Créer une fonction de pagination avec Rails Kaminari
Implémenter une fonction de connexion simple dans Rails
[Ruby on Rails] Fonction de sortie CSV
[Rails] Fonction de publication vocale ~ Cloudinary, CarrierWave
[Rails] Fonction de commentaire (enregistrement / affichage / suppression)
[Rails] Implémentation de fonctions de catégorie plusieurs à plusieurs
[Ruby on Rails] Implémentation de la fonction de commentaire
[Ruby on Rails] DM, fonction de chat
Implémenter la fonction de téléchargement CSV dans Rails
[Rails] Commentaire mémo de procédure d'implémentation
[Ruby on Rails] Fonction de recherche (non sélectionnée)
[Rails] Ajout de la fonction de commentaire Ruby On Rails
Notions de base sur les rails
Rails Examen 1
[Rails] Restrictions de fonction dans l'appareil (connexion / déconnexion)
API Rails
Migration des rails