14
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ancestry[gem]を使った多階層カテゴリー管理

Posted at

概要

'ancestry'は、階層のあるカテゴリーなどツリー構造を管理するgemです。

今回は以下のような三つの階層に枝分かれしたデータを扱います。

○中学一年
 ・数量
  正負の数 / 文字式 / 資料の活用
 ・方程式・関数
  比例・反比例 / 一次方程式
 ・図形
  平面図形 / 立体図形
○中学二年
 ・数量
  式の計算 / 確率
 ・方程式・関数
  連立方程式 / 一次関数
 ・図形
  平行と合同 / 証明 / 図形の性質
○中学三年
 ・数量
  式の計算 / 平方根 / 標本調査
 ・方程式・関数
  二次方程式 / 二次関数
 ・図形
  三平方の定理 / 図形の性質 / 円周角

準備

1. gemファイルに追加

Gemfile
gem 'ancestry'

2. Categoriesテーブルの作成

ターミナル
$ rails g model category
migration_file
class CreateCategories < ActiveRecord::Migration[5.2]
  def change
    create_table :categories do |t|
      t.string :name
      t.string :ancestry
      t.timestamps
    end
  end
end

ancestryカラムにデータの階層を示す値が入ります

ターミナル
$ rake db:migrate

このようなテーブルになります。

id name ancestry

3. Catagoryモデルにhas_ancestryを追加

category.rb
class Category < ApplicationRecord
  has_ancestry
end

githubによると様々なオプションがあります。

4. データをDBに登録

seeds.rb
grade_one = Category.create(name: "中学一年")

one_quantity = grade_one.children.create(name: "数量")
one_function = grade_one.children.create(name: "方程式・関数")
one_shape = grade_one.children.create(name: "図形")

one_quantity.children.create([{name: "正負の数"}, {name: "文字式"}, {name: "資料"}])
one_function.children.create([{name: "比例・反比例"}, {name: "一次方程式"}])
one_shape.children.create([{name: "平面図形"}, {name: "立体図形"}])


grade_two = Category.create(name: "中学二年")

two_quantity = grade_two.children.create(name: "数量")
two_function = grade_two.children.create(name: "方程式・関数")
two_shape = grade_two.children.create(name: "図形")

two_quantity.children.create([{name: "式の計算"}, {name: "確率"}])
two_function.children.create([{name: "連立方程式"}, {name: "一次関数"}])
two_shape.children.create([{name: "平行と合同"}, {name: "証明"}, {name: "図形の性質"}])


grade_three = Category.create(name: "中学三年")

three_quantity = grade_three.children.create(name: "数量")
three_function = grade_three.children.create(name: "方程式・関数")
three_shape = grade_three.children.create(name: "図形")

three_quantity.children.create([{name: "式の計算"}, {name: "平方根"}, {name: "標本調査"}])
three_function.children.create([{name: "二次方程式"}, {name: "二次関数"}])
three_shape.children.create([{name: "三平方の定理"}, {name: "図形の性質"}, {name: "円周角"}])

ancestry(gem)とモデルにhas_ancestryを加えたことにより、childrenメソッドが使えるようになりました。

ターミナル
$ rake db:seed

やっと、以下のようなテーブルができました。

ancestryがNULLなレコードが一番上の階層、ひとつの数値が書かれているレコードが第二階層、/でわけられたふたつの数値があるものが最下層のデータになっています。

id name ancestry
1 中学一年 NULL
2 数量 1
5 正負の数 1/2

親のidとancestryカラムの数値を見ると、それぞれが関連していることがわかります。

値の取得

いよいよ、値の取得方法をおっていきます。

まずはchildrenメソッドで、一つ下の階層の値をすべて取得します。

ターミナル

pry(main)> one_grade = Category.find_by(name: "中学一年")
=> #<Category:0x007fc50033ad98
 id: 1,
 name: "中学一年",
 ancestry: nil,
 
pry(main)> one_grade.children
=> [#<Category:0x007fc5003a9a40
  id: 2,
  name: "数量",
  ancestry: "1",
#<Category:0x007fc5003a96f8
  id: 3,
  name: "方程式・関数",
  ancestry: "1",
 #<Category:0x007fc5003a9540
  id: 4,
  name: "図形",
  ancestry: "1",>]

中学一年.children
 → 数値 / 方程式・関数 / 図形

つぎにindirectsメソッドで一つ階層をまたぎ最下層のデータをすべて取得します。

ターミナル
 pry(main)> one_grade.indirects

=> [#<Category:0x007fc504a8f180
  id: 5,
  name: "正負の数",
  ancestry: "1/2",
 #<Category:0x007fc504a8f040
  id: 6,
  name: "文字式",
  ancestry: "1/2",
#<Category:0x007fc504a8ef00
  id: 7,
  name: "資料",
  ancestry: "1/2",
#<Category:0x007fc504a8edc0
  id: 8,
  name: "比例・反比例",
  ancestry: "1/3",
#<Category:0x007fc504a8ec80
  id: 9,
  name: "一次方程式",
  ancestry: "1/3",
 #<Category:0x007fc504a8eb40
  id: 10,
  name: "平面図形",
  ancestry: "1/4",
 #<Category:0x007fc504a8ea00
  id: 11,
  name: "立体図形",
  ancestry: "1/4",

中学一年.indirects
→ 正負の数 / 文字式 / 資料の活用 / 比例・反比例 / 一次方程式 / 平面図形 / 立体図形

上の階層(親)のデータも取得していきましょう

上の階層はparentメソッドです。

ターミナル
pry(main)> solid_figure = Category.find_by(name: "立体図形")
=> #<Category:0x007fc504a67090
 id: 11,
 name: "立体図形",
 ancestry: "1/4",

pry(main)> solid_figure.parent
=> #<Category:0x007fc500142040
 id: 4,
 name: "図形",
 ancestry: "1",

立体図形.parent
 → 図形

ふたつ上の階層の取得はメソッドがないようなのでparentを連鎖させます

ターミナル
pry(main)> solid_figure.parent.parent

=> #<Category:0x007fc500280c68
 id: 1,
 name: "中学一年",
 ancestry: nil,

立体図形.parent.parent
→ 中学一年

まとめ +αのメソッド

Category.root
→ 中学一年 / 中学二年 / 中学三年

中学一年.children
→ 数量 / 方程式・関数 / 図形

中学一年.indirects
→  正負の数 / 文字式 / 資料の活用 / 比例・反比例 / 一次方程式 / 平面図形 / 立体図形

立体図形.parent
→ 図形

立体図形.parent.parent
→ 中学一年

中学一年.children_ids
→ 2 / 3 / 4

中学一年.indirect_ids
→ 5 / 6 / 7 / 8 / 9 / 10 / 11

他にいくつかのメソッドが用意されています。
詳しくはgithubのREADMEを参照していただきたいです。

なにか間違いがあればご指摘いただけると幸いです!

14
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?