Rails 5路由:动态控制器

时间:2017-08-07 19:45:44

标签: ruby-on-rails

以下路线是否可以动态选择不同的控制器,或者至少是单个控制器动态调用另一个控制器?

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

3 个答案:

答案 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动作。