Rails 4 : Load Seed from TSV


Some days ago, I was requested to enable to load seed data from excel, by my client, in rails 4 project. I told that data to be edited should be managed in database, not excel. But he really requested excel, then I and he decided load data from tsv. Excel is functional, so TSV is appropriate.

Select data area and copy and paste with mouse, Excel data can be pasted as TSV data to text editor, and vise versa.

Environment

  • Ubuntu 14.04 LTS
  • Rails 4.1.8
  • Ruby 2.2.2

Direction

  1. Create feature to load TSV data as a task, and enable to execute with rake.
  2. On executing rake db:seed, execute the task to load TSV.

Usage

Instruction

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

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

Attention

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

Program

The following program creates TSV object first, and read each line. It enables to load big file because it doesn’t load all TSV lines into RAM at once. In ruby, require 'csv' gives us CSV Class that can handle TSV, but I wanted hash of column name and value, and didn’t want to write TSV handling process in main procedure, so I created TSV Class.

Code

Explanation

On executing rake seed_file:load, start from the line includes task load:. :environment is required to use model classes. そこでは 環境変数 TSV に渡された文字列をカンマで区切り、 load_tsv_aspect を実行して データベースにインポートします。

load_tsv_aspect surrounds load_tsv with transaction.

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

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

Now, the task was created. Then, edit seeds.rb.

seeds.rb

To import TSV when rake db:seed is executed, add some codes to seeds.rb. It’s the following 2 lines.

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