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)
我有评论模型,它与项目、用户、更新等可评论模型关联多态。我有一个页面,用户可以在其中看到每个用户的评论。我想在每条评论附近添加一个 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)