読者です 読者をやめる 読者になる 読者になる

リア充爆発日記

You don't even know what ria-ju really is.

rails3 + backbone.jsでデータのやり取りをするために。

RailsでWEB APIサーバを作るときのアーキテクチャをどうするか考える
RESTful APIとWebサイトを1つのアプリケーションで作る

で、この時はAndroidアプリしかAPIを使うクライアントはいなかったんだけど、等々HTMLから使うときが来ました!
この時のために、いろいろ考えて自分なりのRESTfulなAPIを作ってきたつもりだった。

で、ここまでの積み重ねを活かせると思い、backbone.jsも採用したのでなんかもう自分的には伏線回収フェーズが来ました的な。

上記リンクのとおり、APIサブドメインを切って受け付けることにしたけど、backbone.jsはデフォルトだと同一ドメインに対してリクエストを飛ばすので(あたりまえ)これを変更する。
backbone.jsでajaxのリクエスト先を別のHostにする方法


すると問題になるのがsame-originポリシー。これはCORSな対応で回避する。
具体的には、ApplicationControllerあたりにAllow-Originなどを設定してやる。

  before_filter :set_format, :allow_cross_domain_access

  private
  def allow_cross_domain_access
    response.headers["Access-Control-Allow-Origin"] = Settings.allow_origin
    response.headers["Access-Control-Allow-Methods"] = Settings.allow_methods
    response.headers["Access-Control-Allow-Headers"] = Settings.allow_headers
  end

Setting.hogehogeはRailsで環境ごとの設定値を定数的に扱えるSettingslogicね。

で、これでとりあえず指定のOriginからリクエストを発行したブラウザはレスポンスを受け付けてくれるようになる。

が、backbone.jsは各リクエストの前にOPTIONSメソッドを発行してくるので、これの対応が必要。
OPTIONSメソッドについては、この辺。http://www.studyinghttp.net/method#OPTIONS
ざっくりいうと、APIサーバに対して、「おまえんとこは、どんなメソッドとかヘッダに対応してるの?」という問い合わせを本チャンのリクエストの前に送ってくる仕組みらしい。

で、これにRailsで対応するには、
routingで、こんな感じ。

      match '/hoges', to: 'hoges#options', constraints: {method: 'OPTIONS'}
      match '/hoges/:id', to: 'hoges#options', constraints: {method: 'OPTIONS'}

この書き方だと、リソースごとどころか、URLパターンごとにいちいちroutingを定義しなきゃいけないので、ちょっと考えなきゃいけないな、と思ってる。どうしたらいいんだろ??


hoges_controller.rb

  def options
    head :no_content
  end

メソッド名は別になんでもいい。返却するのも、さっき設定したヘッダが重要なのであって、ここはなんとなく204かなぁ、と思って決めた。っていうかどこを探してもOPTIONSメソッドに対してはこのレスポンスコードを返すべき、的な情報がなかった。

rspecでroutingのテストもできた。

  it "routes to #options" do
    expect(options: "http://api.example.com/v1/hoges").to route_to(action: "options", controller: "v1/hoges")
    expect(options: "http://api.example.com/v1/hoges/1").to route_to(action: "options", controller: "v1/hoges", id: "1")
  end

optionsで通るのね・・・。

最後にけっこうハマったのがこれ。
backbone.jsでfetch()でもsave()でもとにかくエラーハンドラが発火してしまう。

あと、別個で認証をどうにかしなきゃいけないけど、それはなんとなくヒミツ。

とりあえず、こんな感じでbackbone.jsからのリクエストがさばけるはず。