以下路线是否可以动态选择不同的控制器,或者至少是单个控制器动态调用另一个控制器?
get '*path' => 'routing#show
例如:
/name-of-a-person => persons#show
/name-of-a-place => places#show
我记得读过一些关于Rails 5的内容可以实现这一点,但我再也找不到它来挽救我的生命。我有可能想象它。
另一个选择是RoutingController
取决于收到的路径会调用不同的控制器。
用例是我在数据库中有一个类型的URL,控制器取决于URL的类型。我在想这样的事情:
get '*path' do |params|
url = Url.find_by!(path: params[:path])
case url.type
when 'person'
'persons#show'
when 'place'
'places#show'
end
end
答案 0 :(得分:2)
到目前为止,我发布了第二个最佳解决方案;还在等着看是否有人知道如何在路线内有效地做到这一点。
class RoutingController < ApplicationController
def show
url = Url.find_by!(path: params[:path])
url.controller_class.dispatch('show', request, response)
end
end
向安德烈提示这个想法。
答案 1 :(得分:1)
您可以定义一个控制器,并在其操作中进行如下操作:
def generic_show
url = Url.find_by!(path: params[:path])
case url.type
when 'person'
controller = PersonController.new
controller.request = request
controller.response = response
controller.show
when 'place'
...
end
end
但是,我建议您将要重用的代码移动到其他类,并在两个控制器中使用它们。它应该更容易理解和维护。
答案 2 :(得分:0)
我认为你可以使用高级路由约束来做到这一点。
来自:http://guides.rubyonrails.org/routing.html#advanced-constraints
如果你有更高级的约束,你可以提供一个响应匹配的对象? Rails应该使用。让我们假设您想将黑名单中的所有用户路由到BlacklistController。你可以这样做:
class BlacklistConstraint
def initialize
@ips = Blacklist.retrieve_ips
end
def matches?(request)
@ips.include?(request.remote_ip)
end
end
Rails.application.routes.draw do
get '*path', to: 'blacklist#index',
constraints: BlacklistConstraint.new
end
我不认为Rails指南示例特别好,因为这个问题基本上可以在应用程序控制器before_action中解决。
在此示例中,约束用于IP过滤,但您也可以实施matches?
来检查它是否是一个人。我会想象像
def matches?(request)
Person.where(slug: request.params[:path]).any?
end
因此,Rails路由器可以决定是否将请求分派给persons#show
动作。