CodeIgniter から参照される既存データベースを残しつつ、新たに Rails で Web API を追加開発した話

環境

既存環境: PHP 5.4 / CodeIgniter 新規環境: Ruby 2.1.3 / Rails 4.1.6

実現したいこと

  • ネイティブアプリ向けに Web API を追加開発したい。
  • Ruby / Rails を採用したい。
  • 既存ソースにはないテストをしっかり書きたい。
  • 既存のデータベース(MySQL)は、そのまま使いまわしたい。

実装のポイント

1. 技術選定

今回は rails-api を選定した。この gem を採用するにあたり、下記の動画が大変参考になった。

#348 The Rails API Gem - RailsCasts

また、テストの書き方も情報量の多さから RSpec を導入することとにした。テストの書き方は下記のサイトを参考にさせてもらった。

今回は Rspec と MySQL を利用したいため、下記の通りプロジェクトを作成した。

  • --skip-test-unit: RSpec を使用するため、デフォルトの Test::Unit を除外
  • --skip-bundle: Gemfile を編集してから bundle install を実行するため、プロジェクト生成時の実行をスキップ
  • --database=mysql: デフォルトの SQLite ではなく、MySQL を使用する
$ bundle exec rails-api new api --skip-bundle --skip-test-unit --database=mysql

2. 既存データベースとの連携

スキーマの取り込み

database.yml を既存のデータベースに向け、以下のコマンドを実行することで、 schema.rb を生成できた。

$ bundle exec rake db:schema:dump

全く同じ疑問を持っていた方がいたため、以下のサイトを参考にさせてもらった。

mysql - Putting Rails over top of an existing database - Stack Overflow

テーブル名の規約対応

既存のテーブル名が Rails の規約に沿っていないことが問題になることが想定されたが、model に self.table_name を追加することで解決できた。まずは、migration を作成したくないので --migration=false オプションをつけてモデルを生成する。

$ bundle exec rails g model user --migration=false

そして、モデルクラスに既存のテーブル名を指定する。

class User < ActiveRecord::Base
  self.table_name = 'user'
end

3. テスト環境の構築

テスト用のデータベースを作成する

テストを実行すると、以下のようなメッセージがでた。

ActiveRecord::NoDatabaseError: Unknown database 'test'Run `$ bin/rake db:create db:migrate` to create your database

既存のデータベースを利用しているとはいえ、これまでテストがなかったのでテスト用のDBを用意する必要がある。

$ bundle exec rake db:create

テスト用のテーブルを作成する

データベースの作成後、再度テストを実行するとまたエラーが発生した。

ActiveRecord::StatementInvalid:
Mysql2::Error: Table 'test.foobar' doesn't exist: SHOW FULL FIELDS FROM `foobar`

今度は、テスト用にテーブルを作成する必要がある。今のところこれが正解。

$ bundle exec rake db:schema:load RAILS_ENV=test

「今のところ」と言っているのは、Rails のバージョンにより仕様が変わっているから。検索すると古い情報が多いので注意が必要。非推奨となった方法は以下の通り。

例えば、これができたのは Rails 4.0 系だけ。4.1 で deprecate された。

Ruby on Rails 4.1 Release Notes — Ruby on Rails Guides

$ bundle exec rake test:prepare
rake aborted!
Don't know how to build task 'test:prepare'

また、以下の方法は Rails 3 系では使えたが 4.1 で deprecate された。現時点ではまだ動くけど WARN がでる。

Ruby on Rails 4.1 Release Notes — Ruby on Rails Guides

$ bundle exec rake db:test:prepare
WARNING: db:test:prepare is deprecated. The Rails test helper now maintains your test schema automatically, see the release notes for details.

rspec の実行

全てのテストを実行

$ bundle exec rake spec:requests

特定のスペックだけ実行

$ bundle exec rspec spec/requests/users_spec.rb

特定のテストケースだけ実行

$ bundle exec rspec spec/requests/users_spec.rb:50