2016-12-14 57 views
2

我有先进的关系许多资源(HABTM/HM/HMT等),所有你能想象,但现在它的时间来写这个API一个美丽的路由。 问题是,我不能鳍约嵌套资源+先进的RO关系做我的路由的最佳实践,这里就是我试图做的事:Rails的5拥有先进的REST风格的关系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的希望路线这#删除用户和用户#补充,我认为这是完全错误的。这些操作不得属于用户控制器。

奖励:

应该看起来像一个多态的路线是什么创造一个Account属于其他2款(与存在验证)2个模型是Source,另一种是多态的[Candidate,User] # for example,(他们是Sociable型号)

回答

3

最好的做法是永远不会*巢资源不止一个级别,只有窝在那里筑巢是必要的,或者提供上下文。

比任何纪录记住一个唯一的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 

在某些情况下,你会想窝巢的创建操作以及资源是否应该在另一个上下文中创建:

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

还规范CRUD操作(显示,索引,创建,销毁,更新)可以增加额外的动词,但是如果你曾经使用'add'或'remove'这样的同义词,或者用'def things'列举或嵌套资源。你做错了。 – max

+0

感谢您的明确解释,但是在最后一个示例中,您将如何使用2个上下文(模型属于2个其他)来包装创建动作?就像我在帖子中的红利问题一样。如何在2个父母需要同时在场时创建关系对象 –

+1

您不需要。使用最重要的模型作为上下文,并将其他关系作为参数传递。 – max