RailsのデータベースをSQLiteからMySQLに変更する

RailsのデフォルトのデータベースはSQLiteですが、後からMySQLに変更するためのメモ。
Railsは4.2.0で、MySQLは5.6です。

  • MySQLのインストール

まずMySQLインストールして下さい。インストール方法は各自環境に合わせてググってください。(投げやり)

MySQLにデータベース作成する。環境ごとに3つ作る。

$ mysql -u root -p
mysql> CREATE DATABASE db_development DEFAULT CHARACTER SET utf8;
mysql> CREATE DATABASE db_test DEFAULT CHARACTER SET utf8;
mysql> CREATE DATABASE db_production DEFAULT CHARACTER SET utf8;

文字コード指定しないとデフォルトだとlatin1でできるので注意。MySQLサーバ側の設定でデフォルト文字コード指定してもよいけど、この場ではとりあえず明示的にCREATE DATABASEで指定してます。

次にMySQLにユーザを作成する。これも環境ごとに3つ作る。

mysql> GRANT ALL PRIVILEGES ON db_development.* TO user_development@localhost IDENTIFIED BY 'pass_development' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON db_test.* TO user_test@localhost IDENTIFIED BY 'pass_test' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON db_production.* TO user_production@localhost IDENTIFIED BY 'pass_production' WITH GRANT OPTION;

試しにユーザログイン確認しておく。

$ mysql -u user_development -p db_development
Enter password:
$ mysql -u user_test -p db_test
Enter password:
$ mysql -u user_production -p db_production
Enter password:

ここからRails側の設定。
config/database.ymlにDB接続先の設定がある。変更前はこんなかんじになってるはず。

# SQLite version 3.x
#   gem install sqlite3
#
#   Ensure the SQLite 3 gem is defined in your Gemfile
#   gem 'sqlite3'
#
default: &default
  adapter: sqlite3
  pool: 5
  timeout: 5000

development:
  <<: *default
  database: db/development.sqlite3

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: db/test.sqlite3

production:
  <<: *default
  database: db/production.sqlite3

以下のように変更する。
共通設定はdefaultでまとめて、環境ごとの差分だけ分ける。

default: &default
  adapter: mysql2
  encoding: utf8
  reconnect: false
  pool: 5
  socket: /var/lib/mysql/mysql.sock

development:
  <<: *default
  database: db_development
  username: user_development
  password: pass_development

test:
  <<: *default
  database: db_test
  username: user_test
  password: pass_test

production:
  <<: *default
  database: db_production
  username: user_production
  password: pass_production

ちなみにソケットファイルのパスは以下のコマンドで調べられる。
各自の環境によって違う可能性があるので適宜読み替えて下さい。

$ mysql_config --socket
/var/lib/mysql/mysql.sock

mysql2アダプタのgemが必要なのでGemfileでsqlite3の行をコメントアウトして、mysql2を追加する。

#gem 'sqlite3'
gem 'mysql2', '~> 0.3.17'

Gemfile更新したらbundle install

$ bundle install

最後にDBのマイグレーションする。

$ bundle exec rake db:migrate

あとは適宜データ投入したり、サーバ立ち上げて動作確認すればOK。

$ bundle exec rake db:seed
$ bundle exec rails s -b 0.0.0.0
  • おまけ

最初CREATE DATABASEするときに文字コード指定していなくて、migrateは成功するけど、実際にデータ投入するとマルチバイト文字で以下のようなエラーが出た。

ActiveRecord::StatementInvalid: Mysql2::Error: Incorrect string value: '\xD0\x90mend...' for column 'message' at row 1

見るからに文字コード怪しいかんじだったので、調べてみたところ、データベース側はlatin1になってた。

mysql> use db_development
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show variables like 'character_set%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

MySQLのデフォルト設定自体を変えてしまうという方法もあるけど、まぁ環境に依らず文字コード指定するクセは付けた方がよいと思うので、データベースを文字コード指定で再作成して再度確認。

mysql> drop database db_development;
mysql> CREATE DATABASE db_development DEFAULT CHARACTER SET utf8;
mysql> use db_development
Database changed
mysql> show variables like 'character_set%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

再度マイグレーションしてデータ投入

$ bundle exec rake db:migrate
$ bundle exec rake db:seed

これで無事にバックエンドがsqliteからMySQLになった。