ActiveRecord単体を使ったTSVファイルからMySQLへのデータ移行（ヘッダー除去）


# はじめに
ActiveRecordを単体で使用して（railsなし）テキストファイルから、データベースへのデータ移行を行いました。今回はタブ区切り形式のデータファイル（TSVファイル）からデータを読み込み、MySQLのデータベースへ格納しました。

# 目次
０．完成コード
１．ActiveRecordのインストール
２．MySQLへの接続設定
３．クラス定義
４．データの読み込みとレコードの作成
&emsp;4-1．with_indexを用いて、ヘッダー部分を除去
&emsp;4-2．多重代入を用いたヘッダーの除去
5．プログラムを実行

# ０．完成コード
```ruby:posts_to_mysql.rb
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
```

# １．ActiveRecordのインストール
まずは、ActiveRecordのインストールを行います。

```bash

$ gem install activerecord
```
次に、MySQLに接続するためのアダプタmysql2というgemもインストールします。ここで以下のように普通にインストールを行おうとするとエラーが出てくる場合があります。

```bash
$ gem install mysql2
```
対処法としては、以下のようにライブラリの場所を指定するオプションを付けて実行します。

```bash
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）](https://qiita.com/aki319809/items/82cabae519cf8e64ccdd)<br>[mysql2 gemインストール時のトラブルシュート
](https://qiita.com/HrsUed/items/ca2e0aee6a2402571cf6)

# ２．MySQLへの接続設定
MySQLのデータベースと接続するための設定を書きます。ここでは、MySQLのデータベース名をtrainingとしています。

```ruby:posts_to_mysql.rb
ActiveRecord::Base.establish_connection(
  adapter: 'mysql2',
  host: 'localhost',
  username: 'root',
  database: 'training'
)
```

# ３．クラス定義
trainingデータベースのテーブルにアクセスするためのクラスを定義します。ここでは、postsテーブルにアクセスするため、ActiveRecord::Baseを継承したPostクラスを定義しています。

```ruby:posts_to_mysql.rb
class Post < ActiveRecord::Base
end
```

# ４．データの読み込みとレコードの作成
メインの、データの移行作業を行います。今回読み込むデータ元のpost.txtの最初の行はヘッダーになっているため、データベースにこの行は入らないようにする必要があります。

```posts.txt
user_id	content  # ヘッダー行
1	Hello
1	World
2	I'm Paul.
4	😀
5	😂
```

#### 4-1．with_indexを用いて、ヘッダー部分を除去
こういったヘッダー除去には、[Enumerator](https://docs.ruby-lang.org/ja/latest/class/Enumerator.html)クラスに定義されている[with_index](https://docs.ruby-lang.org/ja/latest/method/Enumerator/i/with_index.html)メソッドが活躍します。各行について、読み込みの際に順に番号をつけていって、最初の番号である０を持っていたら、データベースには入れないようにします。これで、最初の行であるヘッダー行の格納を防ぐことができます。

```ruby:posts_to_mysql
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](https://docs.ruby-lang.org/ja/latest/class/Enumerator.html)であるFile.foreach('posts.txt')に[with_index](https://docs.ruby-lang.org/ja/latest/method/Enumerator/i/with_index.html)メソッドを使うことで、順に番号をつけていっています。そして、番号が0のとき（i == 0）nextで飛ばしています。番号1以降の行は配列post_with_indexに入り、Post.createでmysqlにおけるpostsテーブルのuser_idカラムと、contentカラムに情報が入ります。
[Enumerator](https://docs.ruby-lang.org/ja/latest/class/Enumerator.html)という概念は分かりづらいですが、いくつか要素があってそれぞれにメソッドを適用できる準備がされているような状態だと考えています。例えば、配列.eachが[Enumerator](https://docs.ruby-lang.org/ja/latest/class/Enumerator.html)オブジェクトです。


####4-2．多重代入を用いたヘッダーの除去

ヘッダー除去の他の方法として、Rubyの多重代入を使うことができます。多重代入については以下の記事を参考にさせていただきました。
[Rubyの多重代入あれこれまとめ](https://qiita.com/yancya/items/c557864f307d429bbde4)
変数に * をつけることで、右辺の残り要素全部を配列として受け取ることができます。

```
x, y, *z = [10, 20, 30, 40]
x #=> 10
y #=> 20
z #=> [30, 40]
```

多重代入を利用して、headerとpostsという配列にデータを分離し、ヘッダーを除去した上でデータベースに入れていくことができます。

```ruby:posts_to_mysql.rb
# データを配列posts_with_headerへ格納
posts_with_header = []
File.foreach('posts.txt') do |line|
  posts_with_header << line.chomp.split("\t")
end

# 多重代入でheaderと配列postsに分ける。1個目の要素がheader、２個目以降が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
```

# ５．プログラムを実行

```bash
$ 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テーブルにヘッダー以外のデータを移行することができました。