この記事↓の続編(?)です
http://qiita.com/IzumiSy/items/e2b2b05d95f55880e7a0
MongoDBのインストール&起動
Bash
brew update
brew install mongodb
mongod --config /usr/local/etc/mongod.conf
Mongoidの追加と設定
Gemfile
...
gem 'mongoid'
gem 'bson_ext'
...
bson_extはMongoDBが内部で使っているデータ交換フォーマットのBSONを高速化するためのgemらしい。
mongoid.yml
development:
sessions:
default:
database: test
hosts:
- localhost:27017
production:
sessions:
default:
uri: <%= ENV['MONGOLAB_URI'] =>
-
development/../default/database
に指定するdbを事前に作っておく必要はない。MongoDBは使う際に自動でデータベースを作成してくれる。 - 今回はherokuでMongoLabを使って動かすため、productionのuriには
MONGOLAB_URI
を指定しておく。
モデル
user.rb
require 'mongoid'
Mongoid.load!('mongoid.yml')
class User
include Mongoid::Document
field :name, type: String
field :email, type: String
validates :name, presence: true
validates :name, uniqueness: true
validates :email, presence: true
validates :email, uniqueness: true
end
- MongoidでDBモデルを追加したいときは
Mongoid::Document
を必ずインクルードする - MySQLやPostgreSQLを使う時とは違ってマイグレーションファイルを用意する必要がない。カラムは直接モデルのクラスの中に
field
を用いて書き足していけば良い。
コントローラ
エラーハンドリングとか適当だけどこんな感じに。
main.rb
require 'sinatra/base'
require 'sinatra/param'
require_relative 'models/user'
class UserRoutes < Sinatra::Base
helpers Sinatra::Param
get '/api/users/:id' do
param :id, String, require: true
user = User.find(params[:id])
body user.to_json
status 200
end
post '/api/user/signup' do
param :name, String, required: true
param :email, String, required: true
user = User.create(name: params[:name], email: params[:email])
body user.to_json
status 202
end
post '/api/user/signin' do
param :name, String, required: true
param :email, String, required: true
# Log-in transaction
status 202
end
end
class Application < Sinatra::Base
configure do
set :raise_errors, true
set :show_exceptions, false
end
enable :logging
use UserRoutes
end
- sinatraでもrailsのstrong_parameterみたいの使いたいな〜と思って調べたら、sinatra-param(https://github.com/mattt/sinatra-param) というのがあるらしいことが分かった。デフォルトだとparamsが指定した条件を満足していないときに
400 Bad Request
を返してくれる - いまのこのコードだと
User.find(...)
のところで存在しないidが指定されたときにMongoidが例外を出してくるので、APIサーバとしてはこれもどうにかしてハンドリングしないとアカン。
テストを書く
テストはRSpecとrack-testを使って書いた
spec_helper.rb
require 'rspec'
require 'json'
require 'rack/test'
require 'database_cleaner'
require_relative '../main.rb'
ENV['RACK_ENV'] = 'test'
RSpec.configure do |config|
include Rack::Test::Methods
def app()
Application.new
end
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
config.profile_examples = 10
end
- database_cleanerを使っているが、今の時点(2015/11/15)での最新版ではMongoidと併せて使うと
DatabaseCleaner.strategy
に:truncation
を指定する箇所でエラー(The 'truncation' strategy does not exist for the mongoid ORM!
)になる。 - database_cleaner自体はMongoidでのtruncationをサポートしているので、これはバグらしい。解決策はGemfileの中でGithubのフェッチ先を指定すること。
Gemfile
...
gem 'database_cleaner', git: 'https://github.com/DatabaseCleaner/database_cleaner.git'
...
テストのファイルそのものはこんな感じに。
基本的にAPIサーバなのでその挙動をチェックするだけのテスト。
user_routes_spec.rb
require_relative "./spec_helper.rb"
describe "GET /api/:users" do
it "should get an error in trying to fetch an undefined user " do
get "/api/users/100"
expect(last_response.status).to eq(500)
end
end
describe "POST /api/user/signup" do
let(:signup_params) {
{ name: "Jonathan",
email: "jonathan@test.com" }
}
it "should NOT make users sign up without params" do
post "/api/user/signup"
expect(last_response.status).to eq(400)
end
it "should make users sign up with params" do
post "/api/user/signup", signup_params
expect(last_response.status).to eq(202)
userId = JSON.parse(last_response.body)['_id']
get "/api/users/#{userId}"
expect(last_response.status).to eq(200)
end
end
describe "POST /api/user/signin" do
it "should not make users sign in without params" do
post "/api/user/signin"
expect(last_response.status).to eq(400)
end
end
-
be_success
とかhave_http_status(:ok)
が使えなくて困ってたら、この辺は全部rspec-railsの持ってるメソッドらしい。なのでここではeqでマッチ指定をする。
参考資料
- http://qiita.com/morizyun/items/b9f7d8f79803d80e9a21
- https://rubygems.org/gems/bson_ext/versions/1.12.3
- http://qiita.com/k-ta-yamada/items/72956c13049d583150e9
- https://github.com/DatabaseCleaner/database_cleaner/issues/299
- http://qiita.com/ori_ika/items/ea29455212f2e5e71e0b
- http://stackoverflow.com/questions/18638745/mongoiderrorsdocumentnotfound-raise-not-found-error