既存環境
PHP5.4 / CodeIgniter
やりたいこと
- ネイティブアプリ向けに Web API を追加開発したい。
- Ruby / Rails で書きたい。
- テストもしっかり書きたい。既存ソースにはない。
- 既存のデータベース(MySQL)は、そのまま使いまわしたい。
問題点
- Rails で Web API を作成する際の情報が少ない
- Rails デフォルトの Database が SQLite
- 既存の Database を利用した情報が意外と少ない
- 既存のテーブル名が 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