Rails 5 RESTful API 具有高级关系
Rails 5 RESTful API with advanced relations
我有很多高级关系的资源(habtm/hm/hmt等..),你能想到的应有尽有,但现在是时候为这个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
.
来创建 Candidate
和 User
之间的关系
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 想将其路由到 users#remove 和 users#add,我认为这是完全错误的。这些操作不得属于用户控制器。
奖金:
创建属于其他 2 个模型(具有存在验证)的 Account
的多态路由应该是什么样子的,这两个模型是 Source
,另一个是多态的 [Candidate,User] # for example
,(他们是 Sociable
型号)
最佳做法是永远不要*嵌套资源超过一层,并且只在需要嵌套或提供上下文的地方嵌套。
请记住,任何具有唯一 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]
使用模块选项让我们在控制器之间区分 "base resource" 及其嵌套表示:
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
我有很多高级关系的资源(habtm/hm/hmt等..),你能想到的应有尽有,但现在是时候为这个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
.
Candidate
和 User
之间的关系
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 想将其路由到 users#remove 和 users#add,我认为这是完全错误的。这些操作不得属于用户控制器。
奖金:
创建属于其他 2 个模型(具有存在验证)的 Account
的多态路由应该是什么样子的,这两个模型是 Source
,另一个是多态的 [Candidate,User] # for example
,(他们是 Sociable
型号)
最佳做法是永远不要*嵌套资源超过一层,并且只在需要嵌套或提供上下文的地方嵌套。
请记住,任何具有唯一 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]
使用模块选项让我们在控制器之间区分 "base resource" 及其嵌套表示:
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