2016-12-14 4 views
2

私は先進的な関係(habtm/hm/hmtなど..)を持つ多くのリソースを持っていますが、今はこのAPIのための美しいルーティングを書く時間です。 問題は、私はここで、RO私のルーティングを行うネストされたリソース+高度の関係についてのベストプラクティスをフィンすることはできません私がしようとしているものです。ここでRails 5先進的な関係を持つRESTful API

は、当該関係

# app/models/candidate.rb 
class Candidate < ApplicationRecord 
    include Sociable, Locatable 

    belongs_to :user 
    has_many :sourcing_accounts 
    has_many :accounts, through: :sourcing_accounts 
    has_many :users, through: :sourcing_accounts 
end 

# app/models/sourcing_account.rb 
class SourcingAccount < ApplicationRecord 
    belongs_to :account 
    belongs_to :candidate 
    belongs_to :user 
end 

# app/models/user.rb 
class User < ApplicationRecord 
    include Sociable 

    has_many :candidates 
    has_many :campaigns 
    has_many :sourcing_account 
end 
と私のモデルです

この例では、SourcingAccountを作成してCandidateUserの間の関係を作成することを許可します。

resources :candidates do 
    resources :accounts 
    resources :users, only: [:index] do 
    post :remove 
    post :add 
    end 
end 

それは生成します。私はこのことについては何も見つからなかった

v1_candidate_user_remove POST /v1/candidates/:candidate_id/users/:user_id/remove(.:format) api/v1/users#remove {:subdomain=>"api", :format=>:json} 
    v1_candidate_user_add POST /v1/candidates/:candidate_id/users/:user_id/add(.:format) api/v1/users#add {:subdomain=>"api", :format=>:json} 

。ベストプラクティスはありますか? そうでない場合は、このケースではどのようになると思いますか?

精度がなければ、Railsはこれをユーザー#removeとusers#addにルーティングしたいと考えていますが、これは全く間違っていると思います。これらのアクションは、ユーザーコントローラに属していてはいけません。

ボーナス:

何が(存在の検証と)2つの他のモデル2つの機種がSourceであり、もう一つは多型[Candidate,User] # for example、(彼らはSociableモデルである)であるに属するAccountを作成するために、多型の経路のようになります。

答えて

3

ベストプラクティスは、リソースを1つ以上のレベルに決して入れ子にすることではなく、ネストが必要な場所にネストするか、コンテキストを提供することです。

一意のIDまたはuidを持つレコードは、コンテキストなしで直接フェッチできます。したがって、不要なメンバールートを入れ子にすると、APIが複雑になり、実際に言葉になります。

DELETE /as/:id 
is a lot better than 
DELETE /as/:a_id/bs/:b_id/c/:id # Are you kidding me! 

例として、古典的なマイクロブログアプリを取るとしましょう:

class User 
    has_many :posts, foreign_key: 'author_id' 
    has_many :comments 
end 

class Post 
    belongs_to :author, class_name: 'User' 
end 

class Comment 
    belongs_to :user 
    belongs_to :post 
end 

あなたのようにルートを宣言することができます:モジュールのオプションを使用

resources :users do 
    scope module: :users do 
    resources :posts, only: [:index] 
    resources :comments, only: [:index] 
    end 
end 

resources :posts do 
    resources :comments, module: :posts, only: [:index, :create] 
end 

resources :comments, only: [:index, :destroy, :update] 

用コントローラ間で私たちをdestinguishすることができます「ベースリソース」とそのネストされた表現:

class API::V1::PostsController < ApplicationController 
    # GET /api/v1/posts 
    def index 
    @posts = Post.all 
    end 

    def show 
    # ... 
    end 
    def destroy 
    # ... 
    end 
    def update 
    # ... 
    end 
end 

# Represents posts that belong to a user 
class API::V1::Users::PostsController < ApplicationController 
    # GET /api/v1/users/:user_id/posts 
    def index 
    @user = User.eager_load(:posts).find(params[:user_id]) 
    respond_with(@user.posts) 
    end 
end 

いくつかのケースでは、あなたが巣を巣にしたいだろうにもリソースが別のコンテキストで作成する必要がある場合にアクションを作成:標準的なCRUD操作(ショー、インデックス、作成、破棄また

class API::V1::Posts::CommentsController < ApplicationController 
    # PATCH /api/v1/posts/:post_id/comments 
    def create 
    @post = Post.find(params[:post_id]) 
    @comment = @post.comments.create(comment_params) 
    respond_with(@comment) 
    end 

    # GET /api/v1/posts/:post_id/comments 
    def index 
    @post = Post.eager_load(:comments).find(params[:post_id]) 
    respond_with(@post.comments) 
    end 
end 
+1

、 update)は、追加の動詞で拡張することができますが、 'add'や' remove'や 'def things'でリストやネストされたリソースのような同義語を使用している場合は、あなたはそれを誤解している。 – max

+0

あなたの明確な説明をお寄せいただきありがとうございます。最後の例では、2つのコンテキスト(モデルは2つのモデルに属します)で作成アクションをどのようにラップしますか?私のポストのボーナス問題のように。 2人の親が同時に存在する必要があるときに関係オブジェクトを作成する方法 –

+1

あなたはしません。最も重要なモデルをコンテキストとして使用し、他の関係をパラメータとして渡します。 – max