【问题标题】:Finding the resource one level above in path (nested resources) - Rails在路径(嵌套资源)中查找上一级资源 - Rails
【发布时间】:2017-04-24 01:29:01
【问题描述】:

我正在构建一个具有如下资源设置的应用:

User
  Team
    Invite
    Project
      Invite

users 有一个teamteams 有很多 projectsusers 可以被邀请加入teams 级别(并且可以访问teams 拥有的任何projects)或project 级别邀请(仅允许被邀请者访问单个项目) .

我正在尝试设置邀请以动态查找其父资源(即:TeamProject)。据我了解,最好的方法是查看路径。目前路径看起来像:

  • /teams/:id/invites/
  • /teams/:id/projects/:id/invites

是否可以从路径中的当前资源向后查看一个“嵌套级别”以在控制器操作中找到父资源(例如:invites#new)?

谢谢!

澄清

我希望能够为teamsprojects 资源使用相同的invites 代码。当调用invites#new 操作时,它会检查路径以查看调用它的资源。如果路径是/teams/:id/invites/,它将返回team,然后我可以通过:id找到,如果路径是/teams/:id/projects/:id/invites,它将返回project,然后我可以通过:id找到。

这可能吗?

【问题讨论】:

  • 你的邀请模型是多态的吗?
  • @leiliu 是的。应该提到这一点!

标签: ruby-on-rails routes rails-routing


【解决方案1】:

首先,您的嵌套深度不应超过一层。

经验法则:资源不得嵌套超过 1 级 深的。一个集合可能需要由它的父级限定,但是一个特定的 成员始终可以通过 id 直接访问,并且不需要 范围(除非由于某种原因 id 不是唯一的)。
- 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 

【讨论】:

  • 感谢您的回复。澄清一下,您是说 URL 的嵌套深度不应超过一级或一般资源?谢谢
  • REST 应用程序中的资源。在某些情况下,URL 会构建层次结构,例如新闻网站,但那是完全不同的球赛。
  • 我添加了一个示例,说明如何为简单的多态资源构建通用控制器 - 如果用例更复杂,则使用模块(Teams::InvitesControllerProjects::InvitesController)和继承而不是创建一个巨大的if...elsif 语句的纠结。
【解决方案2】:

当路线是:

/teams/:team_id/invites/new //note that it should be team_id, not :id,

/teams/:team_id/projects/:project_id/invites/new

您可以随时通过这些参数检查嵌套。如果

params[:project_id].present?

那么你在 /teams/:team_id/projects/:project_id/invites 路由下,invitable_type 应该是 Project。否则,应该是 /teams/:team_id/invites/,invitable_type 应该是 Team。

【讨论】:

  • 感谢您的回复。据我了解,我需要在控制器操作中设置invitable(即:invitable_typeinvitable_id)。有没有办法可以从路径访问此信息,以便我可以在 invites#new 操作中设置 invitable?谢谢
猜你喜欢
  • 2017-07-11
  • 2015-09-29
  • 1970-01-01
  • 1970-01-01
  • 2018-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多