目標
開発環境
・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina
前提
下記実装済み。
・Slim導入
・Bootstrap3導入
・Font Awesome導入
・ログイン機能実装
・投稿機能実装
・多対多のカテゴリー機能実装
・多階層カテゴリー機能実装(準備編)
・多階層カテゴリー機能実装(seed編)
・[多階層カテゴリー機能実装(作成フォーム編)]
(https://qiita.com/matsubishi5/items/4afb4a4f307023126c66)
・[多階層カテゴリー機能実装(編集フォーム編)]
(https://qiita.com/matsubishi5/items/10e61f314f6c56b8690d)
1.コントローラーを編集
# 追記
def category_window
@children = Category.find(params[:parent_id]).children
end
【解説】
① Ajax通信で送られてきたパラメーターに対応するカテゴリーの、子カテゴリーを抽出し、インスタンス変数に代入する。
@children = Category.find(params[:parent_id]).children
2.json.jbuilderファイル
を作成・編集
$ touch app/views/homes/category_window.json.jbuilder
json.array! @children do |children|
json.id children.id
json.name children.name
end
【解説】
① get_category_children
アクションで抽出したレコードを繰り返し処理し、配列を作成する。
json.array! @children do |children|
② 各IDと名前を ①
で作成した配列に格納する。
json.id children.id
json.name children.name
◎ 親カテゴリー(ビジネス)にマウスが乗っている場合の返り値
[
{
"id": 2,
"name": "金融"
},
{
"id": 6,
"name": "経済"
},
{
"id": 9,
"name": "経営"
},
{
"id": 13,
"name": "マーケティング"
},
]
◎ 子カテゴリー(金融)にマウスが乗っている場合の返り値
[
{
"id": 3,
"name": "株"
},
{
"id": 4,
"name": "為替"
},
{
"id": 5,
"name": "税金"
},
]
3.ルーティングを追加
# 追記
get 'get_category/new', to: 'homes#category_window', defaults: { format: 'json' }
4.ビューを編集
body
header
nav.navbar.navbar-default.navbar-fixed-top
.container-fluid
ul.nav.navbar-nav.navbar-right
li.dropdown role='presentation'
a.dropdown-toggle data-toggle='dropdown' href='#' role='button' aria-expanded='false'
i.fas.fa-list-ul
span
| カテゴリーから探す
span.caret
ul.dropdown-menu role='menu'
li role='presentation'
- Category.where(ancestry: nil).each do |parent|
= link_to parent.name, root_path, id: "#{parent.id}", class: 'parent-category'
br
li role='presentation' class='children-list'
br
li role='presentation' class='grandchildren-list'
【解説】
※Bootstrapの書き方については省略します。
① ancestryの値がnil
、つまり親カテゴリーを全て抽出し、プルダウンメニューに表示する。
- Category.where(ancestry: nil).each do |parent|
= link_to parent.name, root_path, id: "#{parent.id}", class: 'parent-category'
② 子カテゴリーを表示する場所を用意する。
li role='presentation' class='children-list'
③ 孫カテゴリーを表示する場所を用意する。
li role='presentation' class='grandchildren-list'
5.JavaScriptファイルを作成・編集
$ touch app/assets/javascripts/category_window.js
$(function() {
function buildChildHTML(children) {
let html = `
<a class="children-category" id="${children.id}" href="/">
${children.name}
</a>
`;
return html;
}
$('.parent-category').on('mouseover', function() {
let id = this.id;
$('.children-category').remove();
$('.grandchildren-category').remove();
$.ajax({
type: 'GET',
url: '/get_category/new',
data: {
parent_id: id,
},
dataType: 'json',
}).done(function(children) {
children.forEach(function(child) {
let html = buildChildHTML(child);
$('.children-list').append(html);
});
});
});
function buildGrandChildHTML(children) {
let html = `
<a class="grandchildren-category" id="${children.id}" href="/">
${children.name}
</a>
`;
return html;
}
$(document).on('mouseover', '.children-category', function() {
let id = this.id;
$.ajax({
type: 'GET',
url: '/get_category/new',
data: {
parent_id: id,
},
dataType: 'json',
}).done(function(children) {
children.forEach(function(child) {
let html = buildGrandChildHTML(child);
$('.grandchildren-list').append(html);
});
$(document).on('mouseover', '.children-category', function() {
$('.grandchildren-category').remove();
});
});
});
});
【解説】
① 子カテゴリーのHTMLを作成する。
function buildChildHTML(children) {
let html = `
<a class="children-category" id="${children.id}" href="/">
${children.name}
</a>
`;
return html;
}
② どの親カテゴリーにマウスが乗っているかによって、子カテゴリーの表示内容を変更する。
$('.parent-category').on('mouseover', function() {
let id = this.id;
$('.children-category').remove();
$('.grandchildren-category').remove();
$.ajax({
type: 'GET',
url: '/get_category/new',
data: {
parent_id: id,
},
dataType: 'json',
}).done(function(children) {
children.forEach(function(child) {
let html = buildChildHTML(child);
$('.children-list').append(html);
});
});
});
◎ 親カテゴリーにマウスが乗った時に発火するイベントを作成する。
$('.parent-category').on('mouseover', function() {});
◎ category_window.json.jbuilder
から送られてきたIDを、変数へ代入する。
let id = this.id;
◎ とりあえず子カテゴリー以下を削除しておく。
$('.children-category').remove();
$('.grandchildren-category').remove();
◎ パラメーター(parent_id)に先ほど作成した変数を設定して、category_window
アクションを非同期で実行する。
$.ajax({
type: 'GET',
url: '/get_category/new',
data: {
parent_id: id,
},
dataType: 'json',
})
◎ Ajax通信が成功した場合は対応する子カテゴリーのHTMLを作成し、表示する。
.done(function(children) {
children.forEach(function(child) {
var html = buildChildHTML(child);
$('.children-list').append(html);
});
});
③孫カテゴリーのHTMLを作成する。
function buildGrandChildHTML(children) {
var html = `
<a class="grandchildren-category" id="${children.id}" href="/">
${children.name}
</a>
`;
return html;
}
④ どの子カテゴリーにマウスが乗っているかによって、孫カテゴリーの表示内容を変更する。(③
とほぼ同じなので説明は省略)
$(document).on('mouseover', '.children-category', function() {
var id = this.id;
$.ajax({
type: 'GET',
url: '/get_category/new',
data: {
parent_id: id,
},
dataType: 'json',
}).done(function(children) {
children.forEach(function(child) {
var html = buildGrandChildHTML(child);
$('.grandchildren-list').append(html);
});
$(document).on('mouseover', '.children-category', function() {
$('.grandchildren-category').remove();
});
});
});
注意
turbolinks
を無効化しないとプルダウンメニューが非同期で動作しないので、必ず無効化しておきましょう。