このWordPressを廃止して自作ブログに置き換えようと絶賛開発中でして、カテゴリデータなどをcsvで管理して db:seed
したいなと思い、実装したのでメモ。
注意ポイント
若干荒い実装ですが、ちょっとした個人開発なら十分な機能だと思います。
要件
やりたいことは
- データはcsvファイルで管理して初期データ投入したい
- seed実行する対象のテーブル指定をしたい
実行イメージはこんな感じ。
$ bin/rails db:seed TABLES=name1,name2,name3
実装
db/seeds
以下に テーブル名.csv
というファイル名でヘッダー付きのcsvファイルを置きます。
db/seeds/ ├── article_categories.csv ├── articles.csv ├── categories.csv └── category_trees.csv
CSVファイルの中身はこんな感じ。
例. categories.csv
id,name,slug 1,"フリーランスエンジニア","freelance-engineer" 2,"キャリア","career" 3,"制度・手続き","office-procedure" 4,"データベース・SQL","database" 5,"Go言語","golang" 6,"老後・資産形成","money" 7,"税金・確定申告","tax" 8,"案件・エージェント","orders" 9,"Udemy","udemy" 10,"プログラミング学習","programming-learning" 11,"副業・複業","side-jobs" 12,"働き方・生活","workstyle-life" 13,"禁煙","%e7%a6%81%e7%85%99" 14,"応用情報技術者試験","ipa-ap" 15,"引越","moving" 16,"Ruby","ruby" 17,"便利サービス・商品","awsome-goods" 18,"書籍","books" 19,"子育て","childcare" 20,"基本情報技術者試験","ipa-fe" 21,"英語学習","english"
db/seed.rb
ではdb/seeds/*.csv
を読み込んでActiveRecordのupsret_all
でデータ投入するようにします。
require "csv" # 実行方法: bin/rails db:seed TABLES=t1,t2,t3 # TABLESで指定したテーブルのみupsert # 未指定の場合はdb/seeds/以下のcsvすべてが多少 pattern = ENV["TABLES"].blank? ? "db/seeds/*.csv" : "db/seeds/{#{ENV["TABLES"]}}.csv" Dir.glob(Rails.root.join(pattern)).each do |path| filename = File.basename(path, ".csv") klass = Module.const_get(filename.classify) data = CSV.read(path, headers: true).map(&:to_h) klass.insert_all(data) if data.present? puts "DONE. file: #{filename}, class: #{klass}" end
コメントに書いた通り、TABLES=categories,tags
といったように指定があればそのファイルのみを、無ければ全ファイルを対象にします。
実行
TABLES指定なし。
TABLES指定あり
補足
今回はマスターデータの量が多くない+初期データ投入が目的なので十分かなと思っています。
大きなプロジェクトだと次のような考慮が必要になってくるでしょう。
- 一気にinsertするのではなく、トランザクション内で数千件ごとに分割
- 追加・更新があったデータのみをupsert,削除した行をdelete