LoginSignup
197
229

More than 3 years have passed since last update.

多階層カテゴリでancestryを使ったら便利すぎた

Last updated at Posted at 2019-04-19

多階層カテゴリを扱おうとして、いろいろ苦労したことと、
結局はancestryというgemを使ってうまくいった(多分)という話です。

完成イメージ

(一部ですが、、、)
・親カテゴリ/子カテゴリ/孫カテゴリがあって、カテゴリ同士に3層の関係性ができている。
・それぞれのカテゴリにアイテムが入っており、カテゴリ分けによってアイテム検索できる。
スクリーンショット 2019-04-20 0.01.55.png

①DB設計

当初、アイテムとカテゴリは多対多になるから中間テーブル作って、カテゴリは細分化して入れとけばいいやろ。
と思ってました、、、
↓当初のER図
スクリーンショット 2019-04-19 23.49.20.png

いざ進めてみると、親子孫の関係性なくね?となり変更。
多階層カテゴリの管理は様々な方法があるようですが、呼び出しがシンプルな
Path Enumeration(経路列挙型)でDBを作成することにしました。

経路をカラムで管理して、経路(Path)基準で表示させましょう、という感じです(あいまいですが)
↓こんな感じ

id path item
1 null レディース
2 1 トップス
3 1/2 Tシャツ

https://kyabatalian.hatenablog.com/entry/2016/12/19/193430
(参考にさせていただいた記事です)

②導入

https://github.com/stefankroes/ancestry
↑に従えばOKです!

Gemfile

gem 'ancestry'
$ bundle install
$ rails g migration add_ancestry_to_[table] ancestry:string:index
$ rake db:migrate
class Category < ApplicationRecord
      has_many :item_categories
    has_many :items, through: :item_categories
    has_ancestry
end
#カテゴリーモデルにアンセストリーを使うよ、って書いておく

準備完了!
↓(ancestoryを使えば多対多でなく、一対多で良さそうです)

class Item < ApplicationRecord

 belongs_to user, foreign_key: 'user_id'
 belongs_to :category
  #(中略
end
class Category < ApplicationRecord
 has_many :items
 has_ancestry
end

スクリーンショット 2019-05-26 13.19.30.png

③レコード投入!

seeds.rb

lady = Category.create(:name=>"レディース")

lady_tops = lady.children.create(:name=>"トップス")
lady_jacket = lady.children.create(:name=>"ジャケット/アウター")

lady_tops.children.create([{:name=>"Tシャツ/カットソー(半袖/袖なし)"}, {:name=>"Tシャツ/カットソー(七分/長袖)"},{:name=>"その他"}])
lady_jacket.children.create([{:name=>"テーラードジャケット"}, {:name=>"ノーカラージャケット"}, {:name=>"Gジャン/デニムジャケット"},{:name=>"その他"}])

ancestryを入れるとchildrenと記述することで直前の変数の子要素として扱うことができます!
なのでレディース(親)トップス(子)Tシャツ(孫)という関係性をレコード作成の時にGemがやってくれるのです!

$ rake db:seed
1   レディース NULL
2   メンズ   NULL
:
13  その他   NULL
14  トップス    1
15  ジャケット/アウター    1
:
19  その他   1
20  Tシャツ/カットソー(半袖/袖なし)    1/14
21  Tシャツ/カットソー(七分/長袖)   1/14
22  シャツ/ブラウス(半袖/袖なし)    1/14
23  シャツ/ブラウス(七分/長袖)   1/14
:

レコード投入完了!

④Viewで表示

コントローラー
def index
  @parents = Category.all.order("id ASC").limit(13)
end
#1層目が13個なのでlimit(13)
ビュー 親要素
- @parents.each do |parent|
 =parent.name


スクリーンショット 2019-04-20 0.52.09.png
*CSSは別途当ててます

子要素

- parent.children.each do |child|
 =child.name                                    

スクリーンショット 2019-04-20 0.54.48.png

孫要素

- child.children.each do |grandchild|
  =grandchild.name

#ちなみに、=grandchild.parent.nameとするとgrandchildrenの親要素を取得できます!

スクリーンショット 2019-04-20 0.54.32.png

⑤結論

便利すぎます。

呼び出しがシンプルでいいですね。
子から親も呼べますので、いろいろな使い方ができるかも?

まだancestryに関するQiitaの記事は少ないように感じますので、
できればGithubのReadMeを参照にすべきかと考えております。

間違っている点、改善点などありましたらコメントいただけますと幸いです:relieved:

参考にさせていただいた記事

https://kyabatalian.hatenablog.com/entry/2016/12/19/193430
https://techracho.bpsinc.jp/hira/2018_03_15/53872
https://qiita.com/NAKANO_Akihito/items/d42a6ceae40933af2352
https://github.com/stefankroes/ancestry

197
229
3

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
197
229