Rails
RSpec

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


既存環境

PHP5.4 / CodeIgniter


やりたいこと


  • ネイティブアプリ向けに Web API を追加開発したい。

  • Ruby / Rails で書きたい。

  • テストもしっかり書きたい。既存ソースにはない。

  • 既存のデータベース(MySQL)は、そのまま使いまわしたい。


問題点


  1. Rails で Web API を作成する際の情報が少ない

  2. Rails デフォルトの Database が SQLite

  3. 既存の Database を利用した情報が意外と少ない

  4. 既存のテーブル名が Rails の規約に沿っていない


解決策


1. Rails で Web API を作成する際の情報が少ない

Rails で Web API を作成する際は rails-api が使いやすかった。この gem を利用するにあたり、下記の参考になった。

参照:#348 The Rails API Gem - RailsCasts

テストの書き方は下記が参考になった。

参照:Rails でつくる API のテストの書き方(RSpec + FactoryGirl) - 彼女からは、おいちゃんと呼ばれています


2. Rails デフォルトの Database が SQLite

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

$ bundle exec rails-api new api --skip-bundle -T -d mysql


3. 既存のDatabaseを利用した情報が意外と少ない

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

$ bundle exec rake db:schema:dump

全く同じ疑問を持っていた方がいた。

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


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

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

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

--> 今のところこれが正解。「今のところ」と行っているのは、コロコロ仕様が変わっているから。

$ bundle exec rake test:prepare

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

--> これができたのは Rails 4.0 系だけ。4.1 で deprecate された。

参照: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.

--> Rails 3 系では使えたが 4.1 で deprecate された。とりあえず動くけど WARN がでる。

参照:Ruby on Rails 4.1 Release Notes — Ruby on Rails Guides


4. 既存のテーブル名が Rails の規約に沿っていない

self.table_nameで解決できる。

まずは、migrationを作成したくないので--migration=falseオプションをつけてモデルを生成する。

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

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

class User < ActiveRecord::Base

self.table_name = 'user'
end


余談


spec ファイルの動的生成

本来は RSpec のインストール (rails g rspec:install) を実行してから rails generator [scaffold|controller|model] で各ファイルを生成すべきとろを忘れてしまっていたので、 spec ファイルが生成されていなかった。そんな時は、 rails g integration_test task で spec ファイルを生成することができた。


rspec の実行


全てのテストを実行

$ bundle exec rake spec:requests


特定のスペックだけ実行

$ bundle exec rspec spec/requests/users_spec.rb 


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

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