LoginSignup
6
10

More than 5 years have passed since last update.

Sinatra+MongoDB(Mongoid)のメモ

Last updated at Posted at 2015-11-15

この記事↓の続編(?)です
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でマッチ指定をする。

参考資料

6
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
10