2016-04-01 33 views
4

application/vnd.rails5_api_test.v1:私はこの形式でAccept headerを通じてバージョンを提供することで、アプリの特定のAPIバージョンにアクセスすることを望んでいました。 Accept headerが指定されていない場合、リクエストは現在のデフォルトバージョンのアプリにルーティングされます。これを処理するために、lib directoryのファイルにapi_constraintsというファイルを作成しました。これはルートに必要です。RailsのAPIバージョン管理、ルーティングの問題

私はv1Users resourcev2Users and Comments resourcesを持っているがありアプリv1v2中の2つのバージョンを作成しました。予想通り すべてが、私はポストマンを使用してヘッダをバージョン1を渡すことによって、URL localhost:3000/commentsを要求したとき、私はすべてのコメントを表示し、comments resourceからの応答を取得していますを除いて、働いていました。しかし、comments resourceはバージョン2であり、要求されたバージョンは1であるため、応答はstatus: 404 Not Foundであると期待しています。

これは、サーバーからの応答です:
制約ファイル、のlib/api_constraints.rb

class APIConstraints 
    def initialize(options) 
    @version = options[:version] 
    @default = options[:default] 
    end 

    def matches?(req) 
    req.headers["Accept"].include?(media_type) || @default 
    end 

    private 

    def media_type 
    "application/vnd.rails5_api_test.v#{@version}" 
    end 
end 

ルートファイル、設定ここで

Started GET "/comments" for 127.0.0.1 at 2016-04-01 20:57:53 +0530 
Processing by Api::V2::CommentsController#index as application/vnd.rails5_api_test.v1 
    Comment Load (0.6ms) SELECT "comments".* FROM "comments" 
[active_model_serializers] User Load (0.9ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]] 
[active_model_serializers] Rendered ActiveModel::Serializer::CollectionSerializer with ActiveModelSerializers::Adapter::JsonApi (4.32ms) 
Completed 200 OK in 7ms (Views: 5.0ms | ActiveRecord: 1.5ms) 

は私の作業ファイルがあります/routes.rb

Rails.application.routes.draw do 
    require "api_constraints" 

    scope module: 'api/v1', constraints: APIConstraints.new(version: 1) do 
    resources :users 
    end 

    scope module: 'api/v2', constraints: APIConstraints.new(version: 2, default: true) do 
    resources :users 
    resources :comments 
    end 
end 
v2の

class Api::V1::UsersController < ApplicationController 

    def index 
    @users = User.all 

    render json: @users, each_serializer: ::V1::UserSerializer 
    end 
end 

ユーザーのコントローラ、API/V2/users_controller.rb:用

class Api::V2::UsersController < Api::V1::UsersController 

    def index 
    @users = User.all 

    render json: @users, each_serializer: ::V2::UserSerializer 
    end 

end 

コメントコントローラV1、API/V1/users_controller.rbため

ユーザーコントローラv2、api/v2/comments_controller.rb

class Api::V2::CommentsController < ApplicationController 

    def index 
    @comments = Comment.all 

    render json: @comments, each_serializer: ::V2::CommentSerializer 
    end 
end 

v1のユーザシリアライザ、user_serializer.rb:v2の

class V1::UserSerializer < ActiveModel::Serializer 
    attributes :id, :name, :email 
end 

ユーザシリアライザ、user_serializer.rb:v2の

class V2::UserSerializer < V1::UserSerializer 

    has_many :comments 
end 

コメントシリアライザ、comment_serializer.rb

class V2::CommentSerializer < ActiveModel::Serializer 
    attributes :id, :description 

    belongs_to :user 
end 

私はこのルートでdefault: trueオプションを削除しようとしましたが、期待どおりに動作しています。しかし、私はそれがデフォルトのオプションで動作するようにしたい。

誰でも私がこの間違いを犯していることを知らせてもらえますか、このアプローチについてのあなたの考えを共有してください。この方法が最善の方法でない場合は、正しい方法で実装してください。私を助けるのに時間がかかる人には、事前に感謝します。 :)乾杯!

+0

あなたの 'comments_controller.rb'も表示されますか? – 7urkm3n

+0

oops!私はそのファイルを見逃してしまった。投稿を 'comments_controller.rb'で更新しました。あなたが思考を持っているかどうかを確認し、私に知らせてください。ありがとう。 – Yash

答えて

1

v1にはコメントがないため、v2は関係なく一致しているため、これは簡単に解決できないと思います。

この方法を使用しているAPIConstraintsはありますか?

def matches?(req) 
    @default || req.headers['Accept'].include?("application/vnd.example.v#{@version}") 
    end 

私はこの方法が少し緩すぎると思うので、バージョンがあるリクエストを無視するとこのように見えます。

def matches?(req) 
    (@default && 
     req.headers['Accept'].grep(/^application/vnd.example.v\d+/$).empty? 
    ) || req.headers['Accept'].include?("application/vnd.example.v#{@version}") 
    end 
+0

あなたの時間のおかげでトーマス。あなたが正しいと思います。私があなたが言及したように私の方法を書いて、あなたに知らせるでしょう。 – Yash

+0

grepを使って 'NoMethodError'を返していました。しかし、私が指摘した方法で試してみましたが、実際に動作しているマッチメソッドを使用しています:)これは私が試したことです: 'req.headers ['Accept']。match(/^application \/vnd \ .example \ .v \ d /)。ブランク?) '。 MatchDataの 'empty?'は 'NoMethodError'を返し、MatchDataがnilなら' empty? 'は同じエラーを返します。' empty? 'メソッドはnilでは動作しません。ですから、私はRails 'blank? 'メソッドを使用しました。今は期待どおりに働いています!この作業:)歓声を得るために私を助けてくれてありがとう! – Yash

+0

あまりにも多くの方法があります:)おそらく 'grep'はちょうど非常に新しい機能です。 'req.headers ['Accept']。any?{| s | s.match(/^application \/vnd \ .example \ .v \ d /)} 'となります。 私の答えを受け入れることを忘れないでください。 –