・ Ruby: 2.5.7 Rails: 5.2.4 ・ Vagrant: 2.2.7 -VirtualBox: 6.1 ・ OS: macOS Catalina
The following has been implemented.
・ Slim introduction ・ Introduction of Bootstrap3 ・ Introduction of Font Awesome -Login function implementation ・ Implementation of posting function -Many-to-many category function implementation ・ Multi-layer category function implementation (preparation) ・ Multi-layer category function implementation (seed)
category.rb
category.rb
def self.category_parent_array_create
category_parent_array = ['---']
Category.where(ancestry: nil).each do |parent|
category_parent_array << [parent.name, parent.id]
end
return category_parent_array
end
category_parent_array = ['---']
nil
, that is, all the parent categories are extracted, and the category name and ID are stored in the array created in (1).Category.where(ancestry: nil).each do |parent|
category_parent_array << [parent.name, parent.id]
end
** * Important points **
[parent.name, parent.id]
➡︎ When displaying the parent category in the select box in the view
The first argument (parent.name) becomes the value displayed in the browser,
The second argument (parent.id) is the value to be sent as a parameter.
①
as a return value.return category_parent_array
book_category.rb
book_category.rb
def self.maltilevel_category_create(book, parent_id, children_id, grandchildren_id)
if parent_id.present? && parent_id != '---'
category = Category.find(parent_id)
BookCategory.create(book_id: book.id, category_id: category.id)
end
if children_id.present? && children_id != '---'
category = Category.find(children_id)
BookCategory.create(book_id: book.id, category_id: category.id)
end
if grandchildren_id.present? && grandchildren_id != '---'
category = Category.find(grandchildren_id)
BookCategory.create(book_id: book.id, category_id: category.id)
end
end
(book, parent_id, children_id, grandchildren_id)
book
: Data of the book to be created
parent_id
: ID of the parent category
children_id
: ID of the child category
grandchildren_id
: ID of grandchild category
if parent_id.present? && parent_id != '---'
category = Category.find(parent_id)
BookCategory.create(book_id: book.id, category_id: category.id)
books_controller.rb
def create
@book = Book.new(book_params)
@book.user_id = current_user.id
if @book.save
BookCategory.maltilevel_category_create(
@book,
params[:parent_id],
params[:children_id],
params[:grandchildren_id]
)
redirect_to books_path
else
@books = Book.all
@category_parent_array = Category.category_parent_array_create
render 'index'
end
end
def index
@book = Book.new
@books = Book.all
@category_parent_array = Category.category_parent_array_create
end
def get_category_children
@category_children = Category.find(params[:parent_id]).children
end
def get_category_grandchildren
@category_grandchildren = Category.find(params[:children_id]).children
end
maltilevel_category_create
method and execute it.BookCategory.maltilevel_category_create(
@book,
params[:parent_id],
params[:children_id],
params[:grandchildren_id]
)
** ◎ Receive the parameters sent by Ajax communication. ** **
params[:parent_id],
params[:children_id],
params[:grandchildren_id]
category_parent_array_create
method to the instance variable.@category_parent_array = Category.category_parent_array_create
def get_category_children
@category_children = Category.find(params[:parent_id]).children
end
def get_category_grandchildren
@category_grandchildren = Category.find(params[:children_id]).children
end
json.jbuilder file
Terminal
$ touch app/views/books/get_category_children.json.jbuilder
ruby:books/get_category_children.json.jbuilder
json.array! @category_children do |children|
json.id children.id
json.name children.name
end
Terminal
$ touch app/views/books/get_category_grandchildren.json.jbuilder
ruby:books/get_category_grandchildren.json.jbuilder
json.array! @category_grandchildren do |grandchildren|
json.id grandchildren.id
json.name grandchildren.name
end
get_category_children
action to create an array.json.array! @category_children do |children|
①
.json.id children.id
json.name children.name
** ◎ Return value when parent category (business) is selected **
[
{
"id": 2,
"name": "Finance"
},
{
"id": 6,
"name": "Economy"
},
{
"id": 9,
"name": "management"
},
{
"id": 13,
"name": "marketing"
},
]
** ◎ When child category (finance) is selected **
[
{
"id": 3,
"name": "stock"
},
{
"id": 4,
"name": "exchange"
},
{
"id": 5,
"name": "tax"
},
]
routes.rb
#Postscript
get 'get_category/children', to: 'books#get_category_children', defaults: { format: 'json' }
get 'get_category/grandchildren', to: 'books#get_category_grandchildren', defaults: { format: 'json' }
slim:books/index.html.slim
.category-form
= label_tag 'Genre'
= select_tag 'parent_id', options_for_select(@category_parent_array), id: 'parent-category', class: 'form-control'
i.fas.fa-chevron-down
br
parent_id
.= select_tag 'parent_id', options_for_select(@category_parent_array), id: 'parent-category', class: 'form-control'
Terminal
$ touch app/assets/javascripts/category_form.js
category_form.js
$(function() {
function appendOption(category) {
let html = `<option value='${category.id}' data-category='${category.id}'>${category.name}</option>`;
return html;
}
function appendChidrenBox(insertHTML) {
let childrenSelectHtml = '';
childrenSelectHtml = `
<div id='children-wrapper'>
<select id='children-category' class='form-control' name='[children_id]'>
<option value='---' data-category='---'>---</option>
${insertHTML}
</select>
<i class='fas fa-chevron-down'></i>
</div>
`;
$('.category-form').append(childrenSelectHtml);
}
function appendGrandchidrenBox(insertHTML) {
let grandchildrenSelectHtml = '';
grandchildrenSelectHtml = `
<div id='grandchildren-wrapper'>
<select id='grandchildren-category' class='form-control' name='[grandchildren_id]'>
<option value='---' data-category='---'>---</option>
${insertHTML}
</select>
<i class='fas fa-chevron-down'></i>
</div>
`;
$('.category-form').append(grandchildrenSelectHtml);
}
$('#parent-category').on('change', function() {
let parentId = document.getElementById('parent-category').value;
if (parentId != '---') {
$.ajax({
url: '/get_category/children',
type: 'GET',
data: {
parent_id: parentId,
},
dataType: 'json',
})
.done(function(children) {
$('#children-wrapper').remove();
$('#grandchildren-wrapper').remove();
let insertHTML = '';
children.forEach(function(children) {
insertHTML += appendOption(children);
});
appendChidrenBox(insertHTML);
})
.fail(function() {
alert('Failed to get the genre');
});
} else {
$('#children-wrapper').remove();
$('#grandchildren-wrapper').remove();
}
});
$('.category-form').on('change', '#children-category', function() {
let childrenId = $('#children-category option:selected').data('category');
if (childrenId != '---') {
$.ajax({
url: '/get_category/grandchildren',
type: 'GET',
data: {
children_id: childrenId,
},
dataType: 'json',
})
.done(function(grandchildren) {
if (grandchildren.length != 0) {
$('#grandchildren-wrapper').remove();
let insertHTML = '';
grandchildren.forEach(function(grandchildren) {
insertHTML += appendOption(grandchildren);
});
appendGrandchidrenBox(insertHTML);
}
})
.fail(function() {
alert('Failed to get the genre');
});
} else {
$('#grandchildren-wrapper').remove();
}
});
});
$(function() {
function appendOption(category) {
let html = `<option value='${category.id}' data-category='${category.id}'>${category.name}</option>`;
return html;
}
** ◎ Set the value to be sent as a parameter. ** **
<option value='${category.id}' data-category='${category.id}'>
** * Important points **
It corresponds to the parameter received by ①
of` 3. Edit controller``.
** ◎ Set the value to be displayed in the select box. ** **
${category.name}
function appendChidrenBox(insertHTML) {
let childrenSelectHtml = '';
childrenSelectHtml = `
<div id='children-wrapper'>
<select id='children-category' class='form-control' name='[children_id]'>
<option value='---' data-category='---'>---</option>
${insertHTML}
</select>
<i class='fas fa-chevron-down'></i>
</div>
`;
$('.category-form').append(childrenSelectHtml);
}
** ◎ Set the parameter name
of the parameter created in ①
. ** **
name='[children_id]
** ◎ Create a child category select box based on the options set in ①
. ** **
${insertHTML}
** ◎ Display the select box of the child category. ** **
$('.category-form').append(childrenSelectHtml);
②
, the explanation is omitted)function appendGrandchidrenBox(insertHTML) {
let grandchildrenSelectHtml = '';
grandchildrenSelectHtml = `
<div id='grandchildren-wrapper'>
<select id='grandchildren-category' class='form-control' name='[grandchildren_id]'>
<option value='---' data-category='---'>---</option>
${insertHTML}
</select>
<i class='fas fa-chevron-down'></i>
</div>
`;
$('.category-form').append(grandchildrenSelectHtml);
}
$('#parent-category').on('change', function() {
let parentId = document.getElementById('parent-category').value;
if (parentId != '---') {
$.ajax({
url: '/get_category/children',
type: 'GET',
data: {
parent_id: parentId,
},
dataType: 'json',
})
.done(function(children) {
$('#children-wrapper').remove();
$('#grandchildren-wrapper').remove();
let insertHTML = '';
children.forEach(function(children) {
insertHTML += appendOption(children);
});
appendChidrenBox(insertHTML);
})
.fail(function() {
alert('Failed to get the genre');
});
} else {
$('#children-wrapper').remove();
$('#grandchildren-wrapper').remove();
}
});
** ◎ Fires when the parent category is selected. ** **
$('#parent-category').on('change', function() {});
** ◎ Get the ID of the selected parent category and assign it to a variable. ** **
let parentId = document.getElementById('parent-category').value;
** ◎ If the parent category is not the default value
Set the ID of the parent category obtained earlier in the parameter (parent_id),
Execute the get_category_children
action asynchronously. ** **
if (parentId != '---') {
$.ajax({
url: '/get_category/children',
type: 'GET',
data: {
parent_id: parentId,
},
dataType: 'json',
})
** ◎ If Ajax communication is successful, create a select box for the child category. Also, if the parent category is changed while the select boxes below the child category are already displayed, Delete the select boxes under the child category and recreate the select boxes for the child categories. ** **
.done(function(children) {
$('#children-wrapper').remove();
$('#grandchildren-wrapper').remove();
let insertHTML = '';
children.forEach(function(children) {
insertHTML += appendOption(children);
});
appendChidrenBox(insertHTML);
})
** ◎ If asynchronous communication fails, an alert is displayed. ** **
.fail(function() {
alert('Failed to get the genre');
});
** ◎ If the parent category is the initial value, delete the child category and below. ** **
} else {
$('#children-wrapper').remove();
$('#grandchildren-wrapper').remove();
}
③
)$('.category-form').on('change', '#children-category', function() {
let childrenId = $('#children-category option:selected').data('category');
if (childrenId != '---') {
$.ajax({
url: '/get_category/grandchildren',
type: 'GET',
data: {
children_id: childrenId,
},
dataType: 'json',
})
.done(function(grandchildren) {
if (grandchildren.length != 0) {
$('#grandchildren-wrapper').remove();
let insertHTML = '';
grandchildren.forEach(function(grandchildren) {
insertHTML += appendOption(grandchildren);
});
appendGrandchidrenBox(insertHTML);
}
})
.fail(function() {
alert('Failed to get the genre');
});
} else {
$('#grandchildren-wrapper').remove();
}
});
** ◎ Some categories do not have grandchildren categories, so conditions are given. (Add conditions to child categories as needed) **
if (grandchildren.length != 0)
If you do not disable turbolinks
, the select box will not work asynchronously, so be sure to disable it.
Multi-layer category function implementation (editing form)
Recommended Posts