在路径中查找上一级资源(嵌套资源)- Rails
Finding the resource one level above in path (nested resources) - Rails
我正在构建一个具有如下资源设置的应用程序:
User
Team
Invite
Project
Invite
users
有一个 team
。 teams
有很多 projects
。 users
可以受邀加入 teams
级别(并有权访问 teams
拥有的任何 projects
)或受邀加入 project
级别(仅授予受邀者访问单个项目的权限)。
我正在尝试设置邀请以动态查找其父资源(即:Team
或 Project
)。据我了解,最好的方法是查看路径。目前路径看起来像:
/teams/:id/invites/
/teams/:id/projects/:id/invites
是否可以从路径中的当前资源回头 "nesting level" 以在控制器操作中找到父资源(例如:invites#new
)?
谢谢!
澄清
我希望能够对 teams
和 projects
资源使用相同的 invites
代码。当调用 invites#new
操作时,它会检查路径以查看调用它的资源。如果路径是 /teams/:id/invites/
,它将 return team
然后我可以通过 :id
找到,如果路径是 /teams/:id/projects/:id/invites
,它将 return project
再一次,我可以通过 :id
.
找到
这可能吗?
当路线为:
/teams/:team_id/invites/new //note that it should be team_id, not :id,
或
/teams/:team_id/projects/:project_id/invites/new
你总是可以通过这些参数来检查嵌套。如果
参数[:project_id].现在?
那么你在/teams/:team_id/projects/:project_id/invites 路由下,invitable_type 应该是项目。否则,它应该是 /teams/:team_id/invites/,invitable_type 应该是 Team.
首先,您的嵌套深度不应超过一层。
Rule of thumb: resources should never be nested more than 1 level
deep. A collection may need to be scoped by its parent, but a specific
member can always be accessed directly by an id, and shouldn’t need
scoping (unless the id is not unique, for some reason).
- Jamis Buck
您的路径应如下所示:
/teams/:team_id/invites
/projects/:project_id/invites
这提供了所有需要的上下文!添加更多的嵌套只会增加膨胀和过度复杂化,并使 API 变得糟糕。
要为嵌套多态资源创建可重用控制器,您可以使用路由关注点:
concerns :inviteable do
resources :invites, shallow: true
end
resources :teams, concerns: :inviteable
resources :projects, concerns: :inviteable
然后您可以为邀请设置一个控制器来检查存在的父参数:
class InvitesController < ApplicationController
before_action :set_parent, only: [:new, :create, :index]
# GET /teams/:team_id/invites/new
# GET /projects/:team_id/invites/new
def new
@invite = @parent.invites.new
end
# GET /teams/:team_id/invites
# GET /projects/:team_id/invites
def index
@invites = @parent.invites
end
# POST /teams/:team_id/invites
# POST /projects/:team_id/invites
def create
@invite = @parent.invites.new(invite_params)
# ...
end
# ...
private
def parent_class
if params[:team_id]
Team
elsif params[:project_id]
Project
end
end
def parent_param
params[ parent_class.model_name.singular_route_key + "_id" ]
end
def set_parent
@parent = parent_class.find(parent_param)
end
end
我正在构建一个具有如下资源设置的应用程序:
User
Team
Invite
Project
Invite
users
有一个 team
。 teams
有很多 projects
。 users
可以受邀加入 teams
级别(并有权访问 teams
拥有的任何 projects
)或受邀加入 project
级别(仅授予受邀者访问单个项目的权限)。
我正在尝试设置邀请以动态查找其父资源(即:Team
或 Project
)。据我了解,最好的方法是查看路径。目前路径看起来像:
/teams/:id/invites/
/teams/:id/projects/:id/invites
是否可以从路径中的当前资源回头 "nesting level" 以在控制器操作中找到父资源(例如:invites#new
)?
谢谢!
澄清
我希望能够对 teams
和 projects
资源使用相同的 invites
代码。当调用 invites#new
操作时,它会检查路径以查看调用它的资源。如果路径是 /teams/:id/invites/
,它将 return team
然后我可以通过 :id
找到,如果路径是 /teams/:id/projects/:id/invites
,它将 return project
再一次,我可以通过 :id
.
这可能吗?
当路线为:
/teams/:team_id/invites/new //note that it should be team_id, not :id,
或
/teams/:team_id/projects/:project_id/invites/new
你总是可以通过这些参数来检查嵌套。如果
参数[:project_id].现在?
那么你在/teams/:team_id/projects/:project_id/invites 路由下,invitable_type 应该是项目。否则,它应该是 /teams/:team_id/invites/,invitable_type 应该是 Team.
首先,您的嵌套深度不应超过一层。
Rule of thumb: resources should never be nested more than 1 level deep. A collection may need to be scoped by its parent, but a specific member can always be accessed directly by an id, and shouldn’t need scoping (unless the id is not unique, for some reason).
- Jamis Buck
您的路径应如下所示:
/teams/:team_id/invites
/projects/:project_id/invites
这提供了所有需要的上下文!添加更多的嵌套只会增加膨胀和过度复杂化,并使 API 变得糟糕。
要为嵌套多态资源创建可重用控制器,您可以使用路由关注点:
concerns :inviteable do
resources :invites, shallow: true
end
resources :teams, concerns: :inviteable
resources :projects, concerns: :inviteable
然后您可以为邀请设置一个控制器来检查存在的父参数:
class InvitesController < ApplicationController
before_action :set_parent, only: [:new, :create, :index]
# GET /teams/:team_id/invites/new
# GET /projects/:team_id/invites/new
def new
@invite = @parent.invites.new
end
# GET /teams/:team_id/invites
# GET /projects/:team_id/invites
def index
@invites = @parent.invites
end
# POST /teams/:team_id/invites
# POST /projects/:team_id/invites
def create
@invite = @parent.invites.new(invite_params)
# ...
end
# ...
private
def parent_class
if params[:team_id]
Team
elsif params[:project_id]
Project
end
end
def parent_param
params[ parent_class.model_name.singular_route_key + "_id" ]
end
def set_parent
@parent = parent_class.find(parent_param)
end
end