プログラミングスクールのチーム開発で、 カテゴリーに親・子・孫の関係をもたせたいと思った時のお話です。 Railsのgem 'ancestry'を導入することで実現することができました。
ancestryのgithub https://github.com/stefankroes/ancestry
開発環境
Ruby 2.5.1 Rails 5.2.3
やりたかったこと
下記の写真のように、(一部抜粋)
・親:メンズ
・子:トップス
・孫:すべて, Tシャツ/カットソー(半袖/袖なし), Tシャツ/カットソー(七分/長袖)...
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を使って、すべてのデータを作成したお話は、別の機会に。
今回は、例で出したテーブルの作成に絞ってお話します。 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