rake task の作り方, submoduleについて、バルクインサート(activerecord-import)の使用法
Rake とは?
自分で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)
入ってますね!!! これはいろいろ応用できそう!。
サブモジュールとは?
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