はじめに
Webサービスを作っているとサービスの成長に合わせて初期のデータ構造を変更することがあります。
そんな時に必要なのが現在のデータを新しいデータ構造に合わせるためのデータコンバートです。
そんなデータコンバートでよく利用する方法を紹介します。
今回の環境
gem 'rails', '4.2.8'
基本的にはRails5系でもデータコンバートのスクリプトは動作すると思います。
他のデータコンバートの方法
マイグレーションにデータコンバートを書く
マイグレーションファイルに書けばDBの構造変更とコンバートの関連性が分かりやすいというメリットがあります。
ただ、マイグレーションファイルに書くと再実行がやりにくいというデメリットがあります。
モデルにデータコンバートを書く
Rails的に書けるのですが、データコンバートが終了すると、ほぼ使われないコードがアプリケーション本体のコードに混ざってしまうので、徐々にFatモデルになっていくのが辛いです。
なるべくデータコンバート処理はアプリケーション本体とは分離したいですね。
SQLを書く
単純なUpdateなどシンプルなコンバートならSQLを直接かいてもよいのですが、条件によってコンバート内容を変更する場合などを考えるとRailsで書きたいところです。
データコンバート専用スクリプトを書く
それではデータコンバート用のスクリプトを書いてみます。
スクリプトは専用のフォルダを作ってそこにまとめるようにしています。
例えば script/convert_users.rb
というファイルを作ります。
User.transaction do
convert_count = 0
User.all.each.with_index(1) do |user, i|
user.nickname = 'NO NAME'
user.save!
convert_count = i
end
puts "User count: #{User.count}"
puts "Convert count: #{convert_count}"
print 'Are you sure?(yes/no) > '
if gets.strip == 'yes'
puts 'committed'
else
puts 'rollback'
raise ActiveRecord::Rollback
end
end
データコンバートはRailsで書きます。
複数データの更新であれば transaction
ブロックで囲みます。
puts "User count: #{User.count}"
puts "Convert count: #{convert_count}"
puts
で実行結果を出力してコンバートの整合性を確認できるようにしています。
print 'Are you sure?(yes/no) > '
if gets.strip == 'yes'
puts 'committed'
else
puts 'rollback'
raise ActiveRecord::Rollback
end
またスクリプト実行時に内容を確認してからコミットできるようにメッセージを表示してコミット or ロールバックを選択できるようにしています。
データコンバート専用スクリプトを実行する
それではスクリプトを実行してみましょう。
ターミナルでRailsのアプリケーションフォルダまで移動してスクリプトを実行します。
rails runner script/convert_users.rb
実行すると下記のように結果が表示されます。
コンバート結果を確認して問題なければ yes
と入力してコンバート結果をコミットします。
User count: 10
Convert count: 10
Are you sure?(yes/no) >
メリット
このようにデータコンバート専用スクリプトを書いておくと、何度でもコマンドラインから実行することが可能となります。アプリケーション本体とも分離しているので本体を汚すこともありません。
また、スクリプトはgitに含めるようにしているので、コードレビューでマイグレーションとの整合性も含めてチェックすることができます。
デメリット
例えばマイグレーションを伴うデータコンバートの場合には、マイグレーション実行 ⇒ データコンバート実行 となるのでコンバートまでに多少の時間差が発生してしまいます。
その為、作りによってはデータの不整合が発生することがあるかもしれません。
- 一旦サービスを停止してから実施する
- 時間差が発生しても問題ない作りにする
- なるはやでデータコンバートを実行する!
上記の様な事を意識する必要があります。
まとめ
今回はよく使うデータコンバートの方法を紹介しました。
データコンバートの方法について「こんな方法もあるよ」などあれば教えてください。