rake task の作り方, submoduleについて、バルクインサート(activerecord-import)の使用法 

Rake とは?

  • RakeはRuby-Makeの略で、Rubyで何かを作ったり、定型的な処理をしたいときに役立ってくれるツール。

自分でWebサイトを作っているとして、いつもページを更新するたびにやらないといけない、定型的な処理があるとする。 この類の手作業は、Rubyを使っている以上決まった処理はスクリプトにやらせたい!!! railsならDB定義をしたあとにrake db:migrateとか必ずやりますよね...

普段何気なく使っているあのrake db:migrateもどこかで作られているものだということです。

$ rake -T

上記のコマンドでrake taskの一覧が確認できます。 rake routesなどももちろん入っています。

そこで今回は自作のrake taskを作っていきます。

rake taskの作成

lib/tasks内にhoge.rakeの形でファイルを作成

今回は

$ rake master_data:load:banks_and_branchesとすると処理が実行されるように作っていきます。

サンプルコード lib/tasks/master_data.rake

namespace :master_data do
  namespace :load do
    desc '銀行データの作成と更新'
    task :banks_and_branches => :environment do # :environment はモデルにアクセスするのに必須

      yml = YAML.load_file("#{ Rails.root }/submodules/zengin-code/data/banks.yml") #各自読み込みたいymlファイルのパスを設定してください

      MasterBank.transaction do
        MasterBank.delete_all # データは最初にリセットする

        master_banks = yml.each_with_object([]) do |(_key, val), ary|
          ary << MasterBank.new(code: val['code'], name: val['name'], name_kana: val['kana'])
        end

        MasterBank.import master_banks # バルクインサート 下部で説明しています
      end
    end
  end
end

submodules/zengin-code/data/banks.yml

このymlファイルに1000件近い銀行データが入っている。。

---
'0001':
  code: '0001'
  name: "みずほ"
  kana: "ミズホ"
  hira: "みずほ"  # 今回hiraとromaはDBで定義していないのでcreateする前に省く処理をプログラム側で実行します
  roma: mizuho #
'0005':
  code: '0005'
  name: "三菱東京UFJ"
  kana: "ミツビシトウキヨウUFJ"
  hira: "みつびしとうきようUFJ"
  roma: mitsubishitoukiyouufj
0009:
  code: 0009
  name: "三井住友"
  kana: "ミツイスミトモ"
  hira: "みついすみとも"
  roma: mitsuisumitomo

$ rake mater_data:load:banks_and_branches

一応確認してみる

$rails db

# select * from master_banks;
 id | code |      name      |        name_kana         |         created_at         |         updated_at
----+------+----------------+--------------------------+----------------------------+----------------------------
 16 | 0001 | みずほ         | ミズホ                   | 2016-08-04 10:25:00.742385 | 2016-08-04 10:25:00.742385
 17 | 0005 | 三菱東京UFJ | ミツビシトウキヨウUFJ | 2016-08-04 10:25:00.782744 | 2016-08-04 10:25:00.782744
 18 | 0009 | 三井住友       | ミツイスミトモ           | 2016-08-04 10:25:00.79938  | 2016-08-04 10:25:00.79938
(3 rows)

入ってますね!!! これはいろいろ応用できそう!。


サブモジュールとは?

https://git-scm.com/book/ja/v1/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E3%82%B5%E3%83%96%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB

http://qiita.com/go_astrayer/items/8667140aef8875742a36

あるプロジェクトで作業をしているときに、プロジェクト内で別のプロジェクトを使わなければならなくなることがよくあります。サードパーティが開発しているライブラリや、自身が別途開発していて複数の親プロジェクトから利用しているライブラリなどがそれにあたります。こういったときに出てくるのが「ふたつのプロジェクトはそれぞれ別のものとして管理したい。だけど、一方を他方の一部としても使いたい」という問題です。

例を考えてみましょう。ウェブサイトを制作しているあなたは、Atom フィードを作成することになりました。Atom 生成コードを自前で書くのではなく、ライブラリを使うことに決めました。この場合、CPAN や gem などの共有ライブラリからコードをインクルードするか、ソースコードそのものをプロジェクトのツリーに取り込むかのいずれかが必要となります。ライブラリをインクルードする方式の問題は、ライブラリのカスタマイズが困難であることと配布が面倒になるということです。すべてのクライアントにそのライブラリを導入させなければなりません。コードをツリーに取り込む方式の問題は、手元でコードに手を加えてしまうと本家の更新に追従しにくくなるということです。

Git では、サブモジュールを使ってこの問題に対応します。サブモジュールを使うと、ある Git リポジトリを別の Git リポジトリのサブディレクトリとして扱うことができるようになります。これで、別のリポジトリをプロジェクト内にクローンしても自分のコミットは別管理とすることができるようになります。

=> 今回はzengin-code(日本の銀行データが入ってる)というgemをsubmoduleとして登録しました。

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

[応用編] 多数レコードをDBに登録する際にはバルクインサートがめちゃ使える

上で、ymlファイルからDBにレコード登録する方法を説明しましたが、多数レコードになる場合はバルクインサートが効率的で良さげです。 端的に言うと、eachによって一回ずつinsert文を実行していたのを、一度のinsert文でクエリをまとめて、DBに流しちゃうというものです。 バルクインサートの方が実行スピードがだいぶ速くなるので、オススメです

activerecord-importというgemを用います。 Gemfile

gem  'activerecord-import'
$ bundle

参考) とてもわかりやすいので参照してみてください。 blog.livedoor.jp

qiita.com