Rails 4 : TSV から seed データ を入れる


Rails で 先般 クライアント から 基本のデータを Excel で入れられるようにしてほしい という依頼がありました。 編集を行うデータだったら編集画面を作って DB で管理したほうがいいことを伝えましたが、 どうしても Excel がいいそうで。 Excel は必要以上に多機能で、すべてのデータをそのままデータベースに反映するのが難しそうであることから()めておいた方がいいと伝えて、 Excel との インポート・エクスポート が容易な TSV で対応することとなりました。 そのときの方法を書いておきます。

TSV は 内容をコピーしてそのまま表計算ソフトに貼り付けることもできますし、表計算ソフトから TSV に貼り付けることもできるので、 Excel でも扱いやすいです。 データが欠損することがあるので、その点で注意が必要です。

環境

  • Ubuntu 14.04 LTS
  • Rails 4.1.8
  • Ruby 2.2.2

方針

  1. TSV 取り込みの機能を task で作り、 rake コマンド で取りこめるようにする。
  2. rake db:seed を行ったときに、 TSV を読み込むタスクを実行するようにする。

使い方

説明

rake seed_file:load TSV=aaa,bbb,ccc/dddaaa.tsvbbb.tsvccc/ddd.tsv をこの順で取り込みます。 特別処理をするコードを書いていない場合は クラス AaaBbbCcc::Ddd が必要になります。

rake seed_file:load を実行しても db/seeds/tsv の下のすべての TSV を取り込むようにはなっていません。 進行中だったプロジェクトにおいて必要性を感じなかったので実装しませんでした。

特別処理とは 下に記述してある category_table.tsv を扱う場合のようなコードをいいます。

注意点

  • TSVdb/seeds/tsv ディレクトリ の下に モデル名のスネークケース + “.tsv” の形で配置されるものとします。 サブディレクトリ内に配置することも可能です。
  • TSV は 1行目をカラム名、2行目以降を値にします。 存在しないカラムが記述されている場合、そのカラムはデータベースに取り込まれません。 _memo という存在しない名前のカラムを作って、備考として利用することも可能です。
  • 一度取り込んだ id は変更しないこと。 id をもとに データ の新規作成・更新を行っているので、 id が変更されると意図せぬデータができます。
  • 取り込んだデータの削除はできません。

プログラム

TSV オブジェクト を作成し、 1行ずつ読み込みます。 一度にすべてをメモリに読み込まないので、大きなファイルでも対応可能です。 ruby では require 'csv' とすることで TSV も扱える CSV クラス が使えるようになるのですが、 カラムと値のハッシュを取得したかったり、 TSV の処理をメイン処理内に書きたくなかったりで、 TSV クラス を作る運びとなりました。

コード

説明

rake seed_file:load が実行されると、 task load: と書いてある行から実行されます。 :environment は モデルクラスを使用するために必要です。 そこでは 環境変数 TSV に渡された文字列をカンマで区切り、 load_tsv_aspect を実行して データベースにインポートします。

load_tsv_aspectload_tsv をトランザクションで囲んだものです。

load_tsv では 環境変数 TSV に渡されていた名前に応じて処理を分けます。 基本的には 1つのTSVを1つのテーブルにロードするだけです。 しかし、 特別に表形式のほうがデータが管理しやすい場合で、そのほうがミスが少ない場合は 1つのTSVに3つのテーブルのデータを保存して管理します。 そういうときのために、 特殊なテーブルには専用の取り込みメソッドを使用します。 上のコードでは category_table というのが 環境変数 TSV に渡された場合に、 category_table.tsv から 3つのテーブルにデータをインポートします。

一般的な場合の load_table_tsv では、 カラムと値をチェックして、 指定されたカラムがテーブルにあればデータとして扱います。 TSVに記述されたカラムがなければ処理を行わないため、 _memo といったカラムを作って、管理のための備考を追加することもできます。

ここまででタスクは完成しました。 ここからは seeds.rb の説明をします。

seeds.rb

rake db:seed を行った際に TSV を読み込むようにするには、 seeds.rb に記述を加える必要があります。 追加するのは次の2行です。

ENV['TSV'] で 取り込み対象の TSV を指定します。 そして Rake::Task['seed_file:load'].invoke でタスクを実行して TSV を取り込みます。