In der Anwendungsentwicklung habe ich eine Kategoriefunktion mit einem Edelstein namens Abstammung hinzugefügt und diese zusammengefasst.
Vorfahren installieren.
gemfile
gem 'ancestry'
Erstellen Sie als Nächstes ein Kategoriemodell.
rails g model category
Beschreibe has_ancestry.
app/models/category.rb
class Category < ApplicationRecord
has_many :posts
has_ancestry
end
Beschreiben Sie es in der Migrationsdatei wie folgt. Für den Index klicken Sie hier (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
Ich werde die Kategorie in der Google-Tabelle beschreiben. Die A-Spalte ist id, die B-Spalte ist name (Kategoriename) und die C-Spalte ist Abstammung (numerischer Wert, der Eltern und Nachkommen unterscheidet). Sie können die Daten speichern, indem Sie die Schritte Datei → Herunterladen → durch Kommas getrennte Werte (aktuelles CSV-Blatt) ausführen.
Legen Sie die heruntergeladene CSV-Datei im Ordner db ab.
Beschreiben Sie Folgendes in der Datei 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
Wenn Sie den Befehl rails db: seed im Terminal ausführen, wird die CSV-Datei gelesen und der DB-Datensatz automatisch generiert. Geben Sie nach foreach die Datei an, die Sie lesen möchten. Die Beschreibung darunter lautet model name.create (Spaltenname => Spalte, die Sie laden möchten). Zeile [0] → Eine Spalte ist id Zeile [1] → Spalte B ist Name (Kategoriename) Zeile [2] → Die Spalte C ist Abstammung (eine Zahl, die Eltern und Nachkommen unterscheidet)
Stellen Sie das Routing von Kinder- und Enkelkategorien im JSON-Format ein.
config/routes.rb
Rails.application.routes.draw do
~Abkürzung~
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
~Abkürzung~
end
Definieren Sie eine übergeordnete Kategorie für den Posts-Controller. Da es an mehreren Stellen verwendet wird, wird es mit before_action definiert.
app/controllers/posts_controller.rb
def set_parents
@parents = Category.where(ancestry: nil)
end
Definieren Sie Methoden für Kinder- und Enkelkategorien im Post-Controller.
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
Erstellen Sie eine json.jbuilder-Datei und konvertieren Sie sie in json-Daten.
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
Legen Sie das Verhalten bei der Auswahl einer Kategorie mit Javascript fest.
: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('Die Kategorie konnte nicht abgerufen werden');
})
}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('Die Kategorie konnte nicht abgerufen werden');
})
}else{
$('#grandchildren_wrapper').remove();
}
})
});
Zeigen Sie das Auswahlfeld für die Kategorie auf der neuen Beitragsseite an.
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 ">
Kategorie
</div>
<div class="lavel__Required">
<%= f.collection_select :category_id, @parents, :id, :name,{ include_blank: "Bitte auswählen"},class:"serect_field", id:"item_category_id" %>
</div>
</div>
</div>
</div>
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
In Javascript erhalten wir die untergeordnete Kategorie und die Enkelkategorie, die zu der übergeordneten Kategorie gehören, in der sich die Maus befindet.
:app/javascript/category.js
$(document).ready(function () {
//Übergeordnete Kategorie anzeigen
$('#categoBtn').hover(function (e) {
e.preventDefault();
e.stopPropagation();
$('#tree_menu').show();
$('.categoryTree').show();
}, function () {
//Ich wage nichts zu schreiben
});
//Zeigen Sie Header-Kategorien asynchron an
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;
}
//Übergeordnete Kategorie anzeigen
$('#categoBtn').hover(function (e) {
e.preventDefault();
e.stopPropagation();
timeOut = setTimeout(function () {
$('#tree_menu').show();
$('.categoryTree').show();
}, 500)
}, function () {
clearTimeout(timeOut)
});
//Untergeordnete Kategorien anzeigen
$('.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("Bitte wählen sie eine Kategorie");
});
}, 400)
}, function () {
clearTimeout(timeParent);
});
//Enkelkind Kategorie anzeigen
$(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("Bitte wählen sie eine Kategorie");
});
}, 400)
},
mouseleave: function () {
clearTimeout(timeChild);
}
}, '.child_btn');
//Bei der Auswahl einer Enkelkategorie
$(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("Bitte wählen sie eine Kategorie");
});
}, 400)
},
mouseleave: function () {
clearTimeout(timeGc);
}
}, '.gc_btn');
//Schaltflächen auf der Kategorielistenseite
$('#all_btn').hover(function (e) {
e.preventDefault();
e.stopPropagation();
$(".categoryTree-grandchild").hide();
$(".categoryTree-child").hide();
$(".category_grandchild").remove();
$(".category_child").remove();
}, function () {
//Wenn Sie nichts schreiben, wird nur die Aktion weitergegeben, wenn sie vom übergeordneten Element abweicht.
});
//Kategorie ausblenden(0 aus dem Kategoriemenü.Es verschwindet, wenn der Cursor 8 Sekunden oder länger entfernt wird)
$(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');
//Verarbeitung von Kategorietasten
$(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');
});
Stellen Sie das Kategorieauswahlfenster auf dem oberen Bildschirm ein.
ruby:app/views/posts/top.html.erb
<div class="item-categories">
<h2>
Kategorieliste
</h2>
<%= link_to posts_path, class: "category-button", id: 'categoBtn' do %>
Suche nach Kategorie
<% 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>
Eine Suchaktion wird mithilfe von member definiert, um Kategorien nach ID zu unterscheiden.
config/routes.rb
resources :posts do
~Abkürzung~
member do
get 'search'
end
~Abkürzung~
end
Die Kategorie, auf die Sie geklickt haben, hängt davon ab, ob es sich um eine übergeordnete Kategorie, eine untergeordnete Kategorie oder eine Enkelkategorie handelt.
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
ruby:app/views/posts/search.html.erb
<div class="item-categories">
<h2>
Kategorieliste
</h2>
<%= link_to posts_path, class: "category-button", id: 'categoBtn' do %>
Suche nach Kategorie
<% 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>
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