Rails link_to 多态父级,可以有嵌套路由

Rails link_to polymorphic parent, which can have a nested route

我有评论模型,它与项目、用户、更新等可评论模型关联多态。我有一个页面,用户可以在其中看到每个用户的评论。我想在每条评论附近添加一个 link,其中包含与该评论相关联的对象的地址。 我可以这样写:

link_to 'show on page', Object.const_get(c.commentable_type).find(c.commentable_id)

但这仅适用于非嵌套路由(如用户)。这是我的路线:

resources :users do
  resources :projects, only: [:show, :edit, :update, :destroy]
end

所以当我需要一个 link 到一个项目页面时,我会得到一个错误,因为我需要一个 link 比如 user_project_path。 如何让 Rails 生成正确的 link?不知何故,我必须找出这个对象的路由是否嵌套,并为嵌套的路由找到父路由

您可以使用一点多态路由魔法。

module CommentsHelper
  def path_to_commentable(commentable)
    resources = [commentable]
    resources.unshift(commentable.parent) if commentable.respond_to?(:parent)
    polymorpic_path(resources) 
  end

  def link_to_commentable(commentable)
     link_to(
       "Show # {commentable.class.model_name.human}",
       path_to_commentable(commentable)
     )
  end
end

class Project < ActiveRecord::Base
  # ...
  def parent
    user
  end
end

link_to_commentable(c.commentable)

但感觉很脏。您的模型不应意识到路由问题。

但解决这个问题的更好方法可能是取消嵌套路由。

除非资源是纯粹嵌套的并且在其父上下文之外没有意义,否则通常最好采用最少的嵌套并考虑资源可能具有不同的表示形式。

/users/:id/projects 可能显示属于某个用户的项目。而 /projects 将显示应用程序中的所有项目。

由于每个项目都有自己的唯一标识符,我们可以在不嵌套的情况下路由各个路由:

GET /projects/:id - projects#show
PATCH /projects/:id - projects#update
DELETE /projects/:id - projects#destroy

这让我们可以在不了解 "parent" 资源的情况下使用多态路由,并且通常会导致更好的 API 设计。

考虑这个例子:

Rails.application.routes.draw do
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html

  resources :projects

  resources :users do
    # will route to User::ProjectsController#index
    resources :projects, module: 'user', only: [:index]
  end

end

class ProjectsController < ApplicationController
  def index
    @projects = Project.all
  end
  # show, edit, etc
end

class User::ProjectsController < ApplicationController
  def index
    @user = User.joins(:projects).find(params[:user_id])
    @projects = @user.comments
  end
end

这将使我们 link 从以下评论的任何项目:

link_to 'show on page', c.commentable

以及任何用户项目:

link_to "#{@user.name}'s projects", polymorpic_path(@user, :projects)