はじめに
ActiveRecordを単体で使用して(railsなし)テキストファイルから、データベースへのデータ移行を行いました。今回はタブ区切り形式のデータファイル(TSVファイル)からデータを読み込み、MySQLのデータベースへ格納しました。
目次
0.完成コード
1.ActiveRecordのインストール
2.MySQLへの接続設定
3.クラス定義
4.データの読み込みとレコードの作成
4-1.with_indexを用いて、ヘッダー部分を除去
4-2.多重代入を用いたヘッダーの除去
5.プログラムを実行
0.完成コード
require 'active_record'
# DB接続設定
ActiveRecord::Base.establish_connection(
adapter: 'mysql2',
host: 'localhost',
username: 'root',
database: 'training'
)
# テーブルにアクセスするためのクラスを定義
class Post < ActiveRecord::Base
end
# レコードの作成
File.foreach('posts.txt').with_index do |line, i|
next if i == 0
post_with_index = line.chomp.split("\t")
Post.create(user_id: post_with_index[0], content: post_with_index[1])
end
# レコード取得
p Post.all
1.ActiveRecordのインストール
まずは、ActiveRecordのインストールを行います。
$ gem install activerecord
次に、MySQLに接続するためのアダプタmysql2というgemもインストールします。ここで以下のように普通にインストールを行おうとするとエラーが出てくる場合があります。
$ gem install mysql2
対処法としては、以下のようにライブラリの場所を指定するオプションを付けて実行します。
gem install mysql2 -v '0.5.2' -- --with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include
参考:
gem install mysql2エラー(Error installing mysql2)
mysql2 gemインストール時のトラブルシュート
2.MySQLへの接続設定
MySQLのデータベースと接続するための設定を書きます。ここでは、MySQLのデータベース名をtrainingとしています。
ActiveRecord::Base.establish_connection(
adapter: 'mysql2',
host: 'localhost',
username: 'root',
database: 'training'
)
3.クラス定義
trainingデータベースのテーブルにアクセスするためのクラスを定義します。ここでは、postsテーブルにアクセスするため、ActiveRecord::Baseを継承したPostクラスを定義しています。
class Post < ActiveRecord::Base
end
4.データの読み込みとレコードの作成
メインの、データの移行作業を行います。今回読み込むデータ元のpost.txtの最初の行はヘッダーになっているため、データベースにこの行は入らないようにする必要があります。
user_id content # ヘッダー行
1 Hello
1 World
2 I'm Paul.
4 😀
5 😂
4-1.with_indexを用いて、ヘッダー部分を除去
こういったヘッダー除去には、Enumeratorクラスに定義されているwith_indexメソッドが活躍します。各行について、読み込みの際に順に番号をつけていって、最初の番号である0を持っていたら、データベースには入れないようにします。これで、最初の行であるヘッダー行の格納を防ぐことができます。
File.foreach('posts.txt').with_index do |line, i|
next if i == 0
post_with_index = line.chomp.split("\t")
Post.create(user_id: post_with_index[0], content: post_with_index[1])
end
p Post.all
EnumeratorであるFile.foreach('posts.txt')にwith_indexメソッドを使うことで、順に番号をつけていっています。そして、番号が0のとき(i == 0)nextで飛ばしています。番号1以降の行は配列post_with_indexに入り、Post.createでmysqlにおけるpostsテーブルのuser_idカラムと、contentカラムに情報が入ります。
Enumeratorという概念は分かりづらいですが、いくつか要素があってそれぞれにメソッドを適用できる準備がされているような状態だと考えています。例えば、配列.eachがEnumeratorオブジェクトです。
####4-2.多重代入を用いたヘッダーの除去
ヘッダー除去の他の方法として、Rubyの多重代入を使うことができます。多重代入については以下の記事を参考にさせていただきました。
Rubyの多重代入あれこれまとめ
変数に * をつけることで、右辺の残り要素全部を配列として受け取ることができます。
x, y, *z = [10, 20, 30, 40]
x #=> 10
y #=> 20
z #=> [30, 40]
多重代入を利用して、headerとpostsという配列にデータを分離し、ヘッダーを除去した上でデータベースに入れていくことができます。
# データを配列posts_with_headerへ格納
posts_with_header = []
File.foreach('posts.txt') do |line|
posts_with_header << line.chomp.split("\t")
end
# 多重代入でheaderと配列postsに分ける。1個目の要素がheader、2個目以降がpostsに入る。
header, *posts = posts_with_header
# postsをDBに入れていく。
posts.each do |post|
Post.create(user_id: post[0], content: post[1])
end
# レコード取得
p Post.all
5.プログラムを実行
$ ruby posts_to_mysql.rb
# =>
#<ActiveRecord::Relation [#<Post id: 1, user_id: 1, content: "Hello">, #<Post id: 2, user_id: 1, content: "World">, #<Post id: 3, user_id: 2, content: "I'm Paul.">, #<Post id: 4, user_id: 4, content: "😀">, #<Post id: 5, user_id: 5, content: "😂">]>
MySQLのpostsテーブルにヘッダー以外のデータを移行することができました。