简体   繁体   English

具有高级关系的Rails 5 RESTful API

[英]Rails 5 RESTful API with advanced relations

I have many resources with advanced relations (habtm/hm/hmt etc..), everything you can imagine, but now it's time to write a beautiful routing for this API. 我有许多具有高级关系的资源(habtm / hm / hmt等。),您可以想象得到的一切,但是现在是时候为该API编写漂亮的路由了。 The problem is, I can't fin the best practices about nested resource + advanced relations ro do my routing, here is what I am trying to do: 问题是,我无法找到有关嵌套资源+高级关系的最佳实践,无法进行路由,这是我要尝试做的事情:

Here are my models with the concerned relations 这是我与相关关系的模型

# 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

For this example, I am willing to permit to create a relation between a Candidate and a User by creating a SourcingAccount . 对于此示例,我愿意通过创建SourcingAccount来允许在CandidateUser之间建立关系。

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

It generates: 它产生:

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}

I did not found anything about this. 我没有发现任何有关此的信息。 Is there best practices ??? 有最佳做法吗? If not, what do you think would be the best for this case ? 如果没有,您认为这种情况下最好的是什么?

Without precisions, Rails wants to route this to users#remove and users#add, which I think is totally wrong. 没有精度,Rails希望将其路由到users#remove和users#add,我认为这是完全错误的。 These actions must not belong to the users controller. 这些动作一定不能属于用户控制器。

Bonus: 奖金:

What should look like a polymorphic route to create an Account belonging to 2 other models (with presence validation) the 2 models are Source and the other one is polymorphic [Candidate,User] # for example , (they are Sociable models) 创建属于其他2个模型(具有状态验证)的Account的多态路线应该看起来像一条多态路线[Candidate,User] # for example ,这2个模型是Source ,而另一个是多态[Candidate,User] # for example ,(它们是Sociable模型)

The best practice is to never* nest resources more than one level and only nest where the nesting is necessary or provides context. 最佳实践是绝不要将资源嵌套超过一个级别,而仅在需要嵌套或提供上下文的地方嵌套。

Remember than any record with a unique id or uid can be fetched directly without context. 请记住,任何具有唯一id或uid的记录都可以在没有上下文的情况下直接获取。 So nesting member routes needlessly will make your API overcomplicated and really wordy. 因此,不必要地嵌套成员路由将使您的API过于复杂且确实冗长。

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

Lets say take a classical microblogging app as an example: 可以说以经典的微博应用程序为例:

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

You could declare the routes as: 您可以将路线声明为:

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]

Using the module option lets us destinguish between the controllers for a "base resource" and its nested representation: 通过使用模块选项,我们可以在控制器之间区分“基本资源”及其嵌套表示形式:

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

In some cases you will want to nest to nest the create action as well if the resources should be created in the context of another: 在某些情况下,如果应该在另一个上下文中创建资源,则也将要嵌套以嵌套create动作:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM