我从来没有找到解决这个问题的好方法。我有以下路线结构:
resources :contents
namespace :admin do
resources :contents
end
当我呼叫content_path(content)
时,我希望id成为内容的slug,而当我呼叫admin_content_path(content)
时,我希望id成为内容的id。我只是希望id不与模型相关(实际上id是模型的to_param
方法的返回值),而是与路径相关。
我想避免为每条路线定义辅助方法,在我看来这是一个微弱的解决方案。
我知道我可以写admin_content_path(id: content.id)
或content_path(id: content.slug)
,但实际上这只是一个黑客攻击。此外,这在form_for
中尤其令人讨厌,因为我无法写
form_for @content
但我被迫使用
form_for @content, url: @content.new_record? ? admin_contents_path : admin_contents_path(id: @content.id)
答案 0 :(得分:1)
通常,您会将路线更改为:
resources :contents, param: :slug
然后覆盖to_param
方法成为:
class Content < ApplicationRecord
def to_param
slug
end
end
最后在您的控制器中,您将Content.find(params[:id]
替换为Content.find_by(slug: params[:slug])
。
当您拨打/contents/foo-bar
时,这会为您提供content_path(content)
这样的网址。
在您的情况下,您还可以创建一个覆盖to_param
方法的子类:
module Admin
class Content < ::Content
def to_param
id && id.to_s # This is the default for ActiveRecord
end
end
end
由于您的admin/contents_controller.rb
在Admin
下被命名空间(例如Admin::ContentsController
),默认情况下会使用Admin::Content
类而不是普通的Content
类,因此,对象本身和所有路径应该如你所愿,包括表格。
答案 1 :(得分:1)
我想说的是两个不同的问题:用户前端的资源生成URL(使用slugs)和管理表单的URL生成。
显然,在您的管理员中,您永远无法编写form_for @resource
,因为您的管理员已命名,因此最低限度至少为form_for [:admin, @resource]
。
假设您在某些模型上有to_param
来返回slug,您可以在管理员后台创建自己的自定义帮助程序,以便始终返回名为{{1}的命名空间的路径并使用记录的/admin/
。
这样做的一种通用方法是在id
根控制器中添加此类代码。
Admin
然后在您的表单中,您可以使用class Admin::AdminController < ApplicationController
helper_method :admin_resource_path, :edit_admin_resource_path
def admin_resource_path(resource)
if resource.new_record?
polymorphic_path([:admin, ActiveModel::Naming.route_key(resource)])
else
polymorphic_path([:admin, ActiveModel::Naming.singular_route_key(resource)], id: resource.id)
end
end
def edit_admin_resource_path(resource)
polymorphic_path([:edit, :admin, ActiveModel::Naming.singular_route_key(resource)], id: resource.id)
end
end
。它适用于用户创建和用户编辑。
您也可以在控制器中使用这些帮助程序来重定向...
答案 2 :(得分:0)
好吧,我找到了一个不错的解决方案,但只在Rails&gt; = 5.1(目前在rc1中),使用全新的direct
method:
namespace :admin do
resources :contents
end
# Maps admin content paths in order to use model.id instead of model.to_param
{ admin_content: :show, edit_admin_content: :edit }.each do |direct_name, action|
direct direct_name do |model, options|
options.merge(controller: 'admin/contents', action: action, id: model.id)
end
end