最近Railsで APIを作ろうと思って、Rails APIモードとDevise Token Authを使ってみたんですが、思わぬところでつまづいてしまいました。今回は、その問題を解決するまでの過程を、私なりにまとめてみました。
最初の状況
まず、こんな感じでプロジェクトを始めました:
-
rails new my_api --apiでAPIモードのRailsプロジェクトを作成 - Gemfileに
gem 'devise_token_auth'を追加 -
bundle installを実行 -
Devise Token Authの設定を行う
ここまではスムーズに進んだんですが、rails s でサーバーを立ち上げて、routesを確認しようとブラウザから http://localhost:3000/rails/info/routes にアクセスしたら
NoMethodError (undefined method `mount_devise_token_auth_for' for #<ActionDispatch::Routing::Mapper:0x00007f8f1c0b0a60>)
というエラーが!
原因を探る
最初は「もしかして、Gemfileに書き忘れたかな?」と思って確認したんですが、ちゃんと書いてありました。
次に、config/routes.rb を見直してみました:
Rails.application.routes.draw do
namespace :api do
namespace :v1 do
mount_devise_token_auth_for 'User', at: 'auth'
# 他のルーティング...
end
end
end
これも一見問題なさそう...。
ここで、「そもそもAPIモードって何が違うんだろう?」と思い、調べてみることにしました。
APIモードの特徴を理解する
Railsガイドを読んでみると、APIモードには以下のような特徴があることがわかりました:
- セッション管理が無効
- クッキーの扱いに制限がある
- ブラウザ向けの機能が多く無効化されている
これを見て、「あれ?DeviseってセッションとかCookieを使うんじゃなかったっけ?」と思い、Devise Token Authのドキュメントも読み直してみました。
なんちゃって解決法
- APIモードを少し緩める
config/application.rbに以下を追加:
config.api_only = false
config.middleware.use ActionDispatch::Cookies
config.middleware.use ActionDispatch::Session::CookieStore
これで、セッションとクッキーが使えるようになるはず...!
- CORSの設定
APIとフロントエンドが別々のサーバーで動く可能性を考えて、CORSの設定もしておきました:
# Gemfile
gem 'rack-cors'
# config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head],
expose: ['access-token', 'expiry', 'token-type', 'uid', 'client']
end
end
- Deviseの設定調整
config/initializers/devise.rbに以下を追加:
config.navigational_formats = [:json]
結果
これらの変更を加えたら...動きました!ブラウザからアクセスしても、あのエラーが出なくなりました。
学んだこと
- APIモードは便利だけど、認証系のgemを使う時は注意が必要
- セッションやクッキーの扱いを理解することが大切
- CORSの設定は早めにしておくと後々楽
参考にしたサイト:
Rails Guides: APIモードについて
Devise Token Auth GitHub
rack-cors gem