多階層カテゴリーの実装
多階層カテゴリー...
rails初心者の方にとっては中々高い壁ではないでしょうか。
そこで、rails初心者である私が実装した三層のカテゴリー検索機能について、説明させて頂ければと思います。
少しでも参考になれば幸いです。
必要なテーブル、カラム
categoriesテーブル
・nameカラム
・parent_idカラム
上記テーブル、及びカラムが必要となります。
parent_idという謎のカラムが存在しますが、説明は後程。
アソシエーション
今回は一つのテーブルで、一層目のカテゴリー、二層目のカテゴリー、三層目のカテゴリーと、全てのカテゴリーを取得出来るよう実装します。
そのためにまず、下記のようなアソシエーションを組みます。
class Category < ApplicationRecord
belongs_to :parent, class_name: :Category
has_many :children, class_name: :Category, foreign_key: :parent_id
end
...上記を見てこう思わないでしょうか。
・なんでcategoryモデルからcategoryモデルにアソシエーション組んでんの?
・そもそもparentとchildrenって何?
これは自己結合モデルというアソシエーションの組み方で、一つのデータベースモデルに全カテゴリーを格納したいけれども、親カテゴリーと子カテゴリーの関係も追えるようにしたい...
そういった時に使用することで、任意のデータの取得が可能になります。
データベース
次に下記のように
categoriesテーブルのデータベース
id | name | parent_id |
---|---|---|
1 | レディース | "" |
2 | トップス | 1 |
3 | パンツ | 1 |
4 | 靴 | 1 |
5 | Tシャツ | 2 |
6 | セーター | 2 |
7 | パーカー | 2 |
parent_idに親カテゴリーのidを入れるよう、データベースにカテゴリーを登録してください。seedファイル等を利用して登録すれば良いと思います。
データの取得
上記アソシエーションの定義、及びカテゴリーの登録によって
@category = Category.find(1)
# 下記でレディースに紐付く子カテゴリーであるトップス、パンツ、靴を全て取得出来る
@category.children
----------------------------
@category = Category.find(2)
# 下記でトップスに紐付く子カテゴリーであるTシャツ、セーター、パーカーを全て取得出来る
@category.children
# 下記でトップスの親カテゴリーであるレディースのカテゴリーを取得出来る
@category.parent
----------------------------
@category = Category.find(5)
# 下記でTシャツの親カテゴリーであるトップスのカテゴリーを取得出来る
@category.parent
# 下記でTシャツの親の親のカテゴリーであるレディースのカテゴリーを取得出来る
@category.parent.parent
任意のカテゴリーを引っ張ってこれるようになります。
また、少し発展的な話をすると
@category = Category.find(params[:id])
@categories = [
# 下記で@categoryを取得
@category,
# 下記で@categoryの子カテゴリーを全て取得
@category.children,
# 下記で@categoryの子カテゴリーの子カテゴリーを全て取得
@category.children.map { |category| category.children }
].flatten.compact
この記述で、idの部分に任意のidを入れると、そのidに関連した全ての子カテゴリーを取得することが出来ます。
例えば、上記の例だとidに1を入れることで、レディース関連のカテゴリーを全て取得することが可能です。
※一番下に記述されているflattenメソッド、compactメソッドはそれぞれ
・複雑化した配列を平坦に返す
・配列の中で発生するnilを取り除いた新しい配列を返す
という機能を持っています。
これらのメソッドを応用することで、何とか三層のカテゴリー検索機能を実装することが出来ました!
参考