スプレッドシート上のデータをseedへ変換するrakeタスクを作成する

概要

ビジネスサイドの人とサービス作るお仕事してるとよくスプレッドシートでマスターデータを受け取ることがある。
なんで、スプレッドシートのデータをどう管理してDBへ格納するか考えた結論のメモ。

やったこと

  • スプレッドシートをtsvで出力
  • tsvからDBへ一時的に格納
    • この時test用DBを使うことで他の環境を汚さないようにする
  • DBへ格納されたレコードをseedファイルとしてエクスポート
  • 環境へのインポートは rake db:seed で行う。
    • seed内では create! ではなく first_or_create! メソッドを使うことで冪等性を担保する

環境

環境はすべてdockerへ固めて実行している。
また、以下の全てのコマンドは docker-compose 内で実行している。

手順

スプレッドシートの用意

適当に idname の存在するスプレッドシートを用意 f:id:y-ohgi:20181026001809p:plain

スプレッドシートからtsvを出力

スプレッドシートcsvで出力すると改行コードがおかしなことになって扱いが面倒なので、tsvでエクスポートする。

f:id:y-ohgi:20181026001822p:plain

こんな感じのファイルがエクスポートされる。

id   name
123 hoge
456 fuga
789 piyo

Gemfileへgemの追加

gem 'seedbank'
gem 'seed_dump'

seedbank はseed管理の拡張を行う
seed_dump はDBのデータをファイルへエクスポートを行う

Taskの作成

$ bundle exec rails g task master

Taskの編集

require 'csv'

namespace :master do
  desc 'tsvからDBへインポートを実行. e.g. $ MASTER_FILE=./dist/master.tsv RAILS_ENV=test bundle exec rake master:import'
  task import: :environment do
    exit unless file = ENV['MASTER_FILE']
    output_file = ENV['OUTPUT_FILE'] || "db/seeds/master.seeds.rb"

    sh "bundle exec rails db:migrate:reset"

    csv = CSV.read(file, headers: true, col_sep: "\t")
    csv.each do |data|
      Master.create(
        id: data[0],
        name: data[1]
      )
    end
    
    sh "bundle exec rake db:seed:dump FILE=#{output_file} MODEL='Master' EXCLUDE='created_at,updated_at'"
    #XXX: ここで first_or_create に変換しないと2度以上 `rake db:seed` が実行できなくなる
    sh "cat #{output_file} | sed -e 's/create!/first_or_create!/' > #{output_file}"

    sh "bundle exec rails db:migrate:reset"
  end
end

seedデータの生成

$ RAILS_ENV=test MASTER_FILE=dist/master.tsv bundle exec rake master:import

データのインポート

$ bundle exec rake db:seed