多階層構造のカテゴリーを実現する、seedを作ってみた

この記事は、『ancestryによる多階層構造の実現』の続きです
https://qiita.com/ATORA1992/items/03eb78e212080072ab9f

メルカリと同じカテゴリーデータを作成しようと、*ancestry*を用いたseedファイルの作り方を考えたお話。

#やりたかったこと
メルカリの膨大なカテゴリーデータを、少しでも楽してseedで作成する。
一部抜粋
[![Image from Gyazo](https://i.gyazo.com/c7ac18a5777c0ff92d65aec4a3aadf3a.png)](https://gyazo.com/c7ac18a5777c0ff92d65aec4a3aadf3a)

#結論
1. 親カテゴリーごとにブロックに分ける
2. ブロックごとに、子カテゴリー配列と、孫カテゴリー配列を用意する
3. その配列を使って、*each*で繰り返し処理を行う

```category.rb
#レディースブロック

#レディースの子カテゴリー配列
lady_child_array = ['トップス','ジャケット/アウター','パンツ','スカート','ワンピース','靴','ルームウェア/パジャマ','レッグウェア','帽子','バッグ','アクセサリー','ヘアアクセサリー','小物','時計','ウィッグ/エクステ','浴衣/水着','スーツ/フォーマル/ドレス','マタニティ','その他']
#レディースの孫カテゴリー配列
lady_grandchild_array = [['すべて','Tシャツ/カットソー(半袖/袖なし)','Tシャツ/カットソー(七分/長袖)','シャツ/ブラウス(半袖/袖なし)','シャツ/ブラウス(七分/長袖)','ポロシャツ','キャミソール','タンクトップ','ホルターネック','ニット/セーター','チュニック','カーディガン/ボレロ','アンサンブル','ベスト/ジレ','パーカー','トレーナー/スウェット','ベアトップ/チューブトップ','ジャージ','その他'], ['すべて','テーラードジャケット','ノーカラージャケット','Gジャン/デニムジャケット','レザージャケット','ダウンジャケット','ライダースジャケット','ミリタリージャケット','ダウンベスト','ジャンパー/ブルゾン','ポンチョ','ロングコート','トレンチコート','ダッフルコート','ピーコート','チェスターコート','モッズコート','スタジャン','毛皮/ファーコート','スプリングコート','スカジャン','その他'], ['すべて','デニム/ジーンズ','ショートパンツ','カジュアルパンツ','ハーフパンツ','チノパン','ワークパンツ/カーゴパンツ','クロップドパンツ','サロペット/オーバーオール','オールインワン','サルエルパンツ','ガウチョパンツ','その他'], ['すべて','ミニスカート','ひざ丈スカート','ロングスカート','キュロット','その他'], ['すべて','ミニワンピース','ひざ丈ワンピース','ロングワンピース','その他'], ['すべて','ハイヒール/パンプス','ブーツ','サンダル','スニーカー','ミュール','モカシン','ローファー/革靴','フラットシューズ/バレエシューズ','長靴/レインシューズ','その他'], ['すべて','パジャマ','ルームウェア'], ['すべて','ソックス','スパッツ/レギンス','ストッキング/タイツ','レッグウォーマー','その他'], ['すべて','ニットキャップ/ビーニー','ハット','ハンチング/ベレー帽','キャップ','キャスケット','麦わら帽子','その他'], ['すべて','ハンドバッグ','トートバッグ','エコバッグ','リュック/バックパック','ボストンバッグ','スポーツバッグ','ショルダーバッグ','クラッチバッグ','ポーチ/バニティ','ボディバッグ/ウェストバッグ','マザーズバッグ','メッセンジャーバッグ','ビジネスバッグ','旅行用バッグ/キャリーバッグ','ショップ袋','和装用バッグ','かごバッグ','その他'], ['すべて','ネックレス','ブレスレット','バングル/リストバンド','リング','ピアス(片耳用)','ピアス(両耳用)','イヤリング','アンクレット','ブローチ/コサージュ','チャーム','その他'], ['すべて','ヘアゴム/シュシュ','ヘアバンド/カチューシャ','ヘアピン','その他'], ['すべて','長財布','折り財布','コインケース/小銭入れ','名刺入れ/定期入れ','キーケース','キーホルダー','手袋/アームカバー','ハンカチ','ベルト','マフラー/ショール','ストール/スヌード','バンダナ/スカーフ','ネックウォーマー','サスペンダー','サングラス/メガネ','モバイルケース/カバー','手帳','イヤマフラー','傘','レインコート/ポンチョ','ミラー','タバコグッズ','その他'], ['すべて','腕時計(アナログ)','腕時計(デジタル)','ラバーベルト','レザーベルト','金属ベルト','その他'], ['すべて','前髪ウィッグ','ロングストレート','ロングカール','ショートストレート','ショートカール','その他'], ['すべて','浴衣','着物','振袖','長襦袢/半襦袢','水着セパレート','水着ワンピース','水着スポーツ用','その他'], ['すべて','スカートスーツ上下','パンツスーツ上下','ドレス','パーティーバッグ','シューズ','ウェディング','その他'], ['すべて','トップス','アウター','インナー','ワンピース','パンツ/スパッツ','スカート','パジャマ','授乳服','その他'], ['すべて','コスプレ','下着','その他']]

parent = Category.create(name: 'レディース')
lady_child_array.each_with_index do |child, i|
 child = parent.children.create(name: child)
 lady_grandchild_array[i].each do |grandchild|
   child.children.create(name: grandchild)
 end
end

#メンズブロック

#メンズの子カテゴリー配列
mens_child_array = ['トップス','ジャケット/アウター','パンツ','靴','バッグ','スーツ','帽子','アクセサリー','小物','時計','水着','レッグウェア','アンダーウェア','その他',]
#メンズの孫カテゴリー配列
mens_grandchild_array = [['すべて','Tシャツ/カットソー(半袖/袖なし)','Tシャツ/カットソー(七分/長袖)','シャツ','ポロシャツ','タンクトップ','ニット/セーター','パーカー','カーディガン','スウェット','ジャージ','ベスト','その他'], ['すべて','テーラードジャケット','ノーカラージャケット','Gジャン/デニムジャケット','レザージャケット','ダウンジャケット','ライダースジャケット','ミリタリージャケット','ナイロンジャケット','フライトジャケット','ダッフルコート','ピーコート','ステンカラーコート','トレンチコート','モッズコート','チェスターコート','スタジャン','スカジャン','ブルゾン','マウンテンパーカー','ダウンベスト','ポンチョ','カバーオール','その他'], ['すべて','デニム/ジーンズ','ワークパンツ/カーゴパンツ','スラックス','チノパン','ショートパンツ','ペインターパンツ','サルエルパンツ','オーバーオール','その他'], ['すべて','スニーカー','サンダル','ブーツ','モカシン','ドレス/ビジネス','長靴/レインシューズ','デッキシューズ','その他'], ['すべて','ショルダーバッグ','トートバッグ','ボストンバッグ','リュック/バックパック','ウエストポーチ','ボディーバッグ','ドラムバッグ','ビジネスバッグ','トラベルバッグ','メッセンジャーバッグ','エコバッグ','その他'], ['すべて','スーツジャケット','スーツベスト','スラックス','セットアップ','その他'], ['すべて','キャップ','ハット','ニットキャップ/ビーニー','ハンチング/ベレー帽','キャスケット','サンバイザー','その他'], ['すべて','ネックレス','ブレスレット','バングル/リストバンド','リング','ピアス(片耳用)','ピアス(両耳用)','アンクレット','その他'], ['すべて','長財布','折り財布','マネークリップ','コインケース/小銭入れ','名刺入れ/定期入れ','キーケース','キーホルダー','ネクタイ','手袋','ハンカチ','ベルト','マフラー','ストール','バンダナ','ネックウォーマー','サスペンダー','ウォレットチェーン','サングラス/メガネ','モバイルケース/カバー','手帳','ストラップ','ネクタイピン','カフリンクス','イヤマフラー','傘','レインコート','ミラー','タバコグッズ','その他'], ['すべて','腕時計(アナログ)','腕時計(デジタル)','ラバーベルト','レザーベルト','金属ベルト','その他'], ['すべて','一般水着','スポーツ用','アクセサリー','その他'], ['すべて','ソックス','レギンス/スパッツ','レッグウォーマー','その他'], ['すべて','トランクス','ボクサーパンツ','その他'], ['すべて']]

parent = Category.create(name: 'メンズ')
mens_child_array.each.each_with_index do |child, i|
 child = parent.children.create(name: child)
 mens_grandchild_array[i].each do |grandchild|
   child.children.create(name: grandchild)
 end
end

~省略~

#その他ブロック

#その他の子カテゴリー配列
other_child_array = ['まとめ売り','ペット用品','食品','飲料/酒','日用品/生活雑貨/旅行','アンティーク/コレクション','文房具/事務用品','事務/店舗用品','その他']
#その他の孫カテゴリー配列
other_grandchild_array = [['すべて'], ['すべて','ペットフード','犬用品','猫用品','魚用品/水草','小動物用品','爬虫類/両生類用品','かご/おり','鳥用品','虫類用品','その他'], ['すべて','菓子','米','野菜','果物','調味料','魚介類(加工食品)','肉類(加工食品)','その他 加工食品','その他'], ['すべて','コーヒー','ソフトドリンク','ミネラルウォーター','茶','ウイスキー','ワイン','ブランデー','焼酎','日本酒','ビール、発泡酒','その他'], ['すべて','タオル/バス用品','日用品/生活雑貨','洗剤/柔軟剤','旅行用品','防災関連グッズ','その他'], ['すべて','雑貨','工芸品','家具','印刷物','その他'], ['すべて','筆記具','ノート/メモ帳','テープ/マスキングテープ','カレンダー/スケジュール','アルバム/スクラップ','ファイル/バインダー','はさみ/カッター','カードホルダー/名刺管理','のり/ホッチキス','その他'], ['すべて','オフィス用品一般','オフィス家具','店舗用品','OA機器','ラッピング/包装','その他'], ['すべて']]

parent = Category.create(name: 'その他')
other_child_array.each.each_with_index do |child, i|
 child = parent.children.create(name: child)
 other_grandchild_array[i].each do |grandchild|
   child.children.create(name: grandchild)
 end
end
```

##ポイント
**孫カテゴリー配列の作り方**
1. 子カテゴリーは、単純に配列に要素を記述するだけで大丈夫
2. 孫カテゴリーは、<font color="Red">配列の中に配列要素を作る</font>
3. 孫カテゴリーの<font color="Red">配列要素の順番を、子カテゴリー要素の順番と対応させる</font>

わかりにくいと思うので、一部抜粋して考えてみる

```category.rb
#レディースブロック

#レディースの子カテゴリー配列
lady_child_array = ['トップス','ジャケット/アウター','パンツ']
#レディースの孫カテゴリー配列
lady_grandchild_array = [['すべて','Tシャツ/カットソー(半袖/袖なし)'..etc], ['すべて','テーラードジャケット','ノーカラージャケット'..etc], ['すべて','デニム/ジーンズ','ショートパンツ'..etc]]

parent = Category.create(name: 'レディース')
lady_child_array.each_with_index do |child, i|
 child = parent.children.create(name: child)
 lady_grandchild_array[i].each do |grandchild|
   child.children.create(name: grandchild)
 end
end
```
子カテゴリーの要素の順番は
1. トップス
2. ジャケット/アウター
3. パンツ

孫カテゴリーの配列要素の順番は
1. ['すべて','Tシャツ/カットソー(半袖/袖なし)'..etc]
2. ['すべて','テーラードジャケット','ノーカラージャケット'..etc]
3. ['すべて','デニム/ジーンズ','ショートパンツ'..etc]

・子カテゴリーの"トップス"は、要素の1番目なので、孫カテゴリーの配列要素1番目は"トップス"に関連するカテゴリー配列

・子カテゴリーの"ジャケット/アウター"は、要素の2番目なので、孫カテゴリーの配列要素2番目は"ジャケット/アウター"に関連するカテゴリー配列

・子カテゴリーの"パンツ"は、要素の3番目なので、孫カテゴリーの配列要素3番目は"パンツ"に関連するカテゴリー配列

このように、順番が対応していれば、*each*がうまいことやってくれます。

#注意点
配列の準備は、ゴリゴリコピーでなんとかしました。
コピーして、正規表現で欲しい形に成形するなどした方が楽かもしれません

#Tips
seedファイルはテーブルごとに分割して作成しました。
分割した方が管理しやすいと思います。
以下の記事を参考にさせていただきました。
https://qiita.com/t-kusakabe/items/232b47dac4c2d355e154
https://qiita.com/masaki7555/items/d65f56958020cbca5ee0