LoginSignup
30
34

More than 3 years have passed since last update.

ancestryによる多階層構造の実現

Last updated at Posted at 2019-07-06

プログラミングスクールのチーム開発で、
カテゴリーに親・子・孫の関係をもたせたいと思った時のお話です。
Railsのgem 'ancestry'を導入することで実現することができました。

ancestryのgithub
https://github.com/stefankroes/ancestry

開発環境

Ruby 2.5.1
Rails 5.2.3

やりたかったこと

下記の写真のように、(一部抜粋)
・親:メンズ
・子:トップス
・孫:すべて, Tシャツ/カットソー(半袖/袖なし), Tシャツ/カットソー(七分/長袖)...
カテゴリーの項目に対して、関係性をもたせる。
Image from Gyazo

ancestry導入でできること

概略をいうと、以下のテーブルのように、レコードごとの関係性を示すパス(カラム名:ancestry。gemのREADMEにのっとり、名前を決めています)を簡単に作成することができます。
また、データの取り出しも、パスを使うことで簡単に行うことができます。

id name ancestry
1 メンズ nil
2 トップス 1
3 すべて 1/2
4 Tシャツ/カットソー(半袖/袖なし) 1/2
5 Tシャツ/カットソー(七分/長袖) 1/2

・親のパス(ancestry)はnil
・子のパスは、親のid
・孫のパスは、(親のid)/(子のid)
となります。

実際に上記のDBを作るまで

まずはじめに、

id name

のテーブルを作成してください。

ancestryの下準備

下記のREADMEに従えば大丈夫です
https://github.com/stefankroes/ancestry

Gemfile

Gemfileに記述を追加

gem 'ancestry'

ターミナル上で、下記のコードを実行

$ bundle install
$ rails g migration add_ancestry_to_category ancestry:string:index

categoriesテーブルにancestryのカラムを作成

migration.rb
class AddAncestryToCategory < ActiveRecord::Migration[5.2]
  def change
    add_column :categories, :ancestry, :string
    add_index :categories, :ancestry 
  end
end

categoryモデルにancestryを明示

category.rb
class Category < ApplicationRecord
   ~省略~
   has_ancestry
end

これで、テーブルの準備は整いました。

ancestryのメソッドを用いてデータ挿入

カテゴリーデータは、アプリの初期データとして欲しかったので、seedを使いました。
seedを使って、すべてのデータを作成したお話は、別の機会に。
https://qiita.com/ATORA1992/items/617088f885117532454e

今回は、例で出したテーブルの作成に絞ってお話します。
ancestryを導入すると、便利なメソッドを使うことができます。(一部抜粋)

method return value
children 子供のレコードを取り出せます

すべてのメソッドは
https://github.com/stefankroes/ancestry
Navigating your treeを参照してください。

上記のメソッドは、データの取り出しだけではなく、作成時にも使うことができます。
これらを使うと、、、

mens = Category.create(:name=>"メンズ")

mens_tops = mens.children.create(:name=>"トップス")

mens_tops.children.create([{:name=>"すべて"}, {:name=>"Tシャツ/カットソー(半袖/袖なし)"},{:name=>"Tシャツ/カットソー(七分/長袖)"}])

とすることで、勝手にancestryにパスのデータも作成してくれます。

id name ancestry
1 メンズ nil
2 トップス 1
3 すべて 1/2
4 Tシャツ/カットソー(半袖/袖なし) 1/2
5 Tシャツ/カットソー(七分/長袖) 1/2

細かく見ていくと
親カテゴリーをまずは作成

mens = Category.create(:name=>"メンズ")

作成した親レコードに対して、".children"メソッドで、子供であることを明示し、子カテゴリーを作成

mens_tops = mens.children.create(:name=>"トップス")

同様に、作成した子レコードに対して、".children"メソッドで、子供の子(孫)であることを明示し、孫カテゴリーを作成

mens_tops.children.create([{:name=>"すべて"}, {:name=>"Tシャツ/カットソー(半袖/袖なし)"},{:name=>"Tシャツ/カットソー(七分/長袖)"}])

まとめ

多階層構造を作るなら、ancestryが便利です。
一つのテーブル内で関係性をもたせることができるので、中間テーブルとか、外部キーとかもいらないですしね。
今回は、データの保存に関してのみ書きましたが、取り出しも、メソッドを使うと簡単に行うことができます。
それに関しては、別記事にまとめたいと思います。

参考

https://github.com/stefankroes/ancestry
https://qiita.com/Sotq_17/items/120256209993fb05ebac
https://qiita.com/NAKANO_Akihito/items/d42a6ceae40933af2352

30
34
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
30
34