Rails路由更复杂:约束

时间:2015-02-08 14:41:13

标签: ruby-on-rails ruby ruby-on-rails-4

目前,如果你想添加一个约束,有许多方法可以做到,但正如我现在所看到的,你只能包含一个被调用的权威方法。 E.g。

Class Subdomain

  # Possible other `def`s here, but it's self.matches? that gets called.

  def self.matches?( request )
    # Typical subdomain check here
    request.subdomain.present? && request.subdomain != "www"
  end

end

上述方法存在的问题是它没有处理以www为前缀的路由,即admin和www.admin是不可分割的。可以添加更多逻辑,但如果在一组静态子域(例如admin,support和api)上需要这些逻辑,则您当前需要创建SubdomainAdmin,SubdomainSupport等....

这可以通过routes.rb中的正则表达式解决:

管理员

:constraints => { :subdomain => /(www.)?admin/ }

API

:constraints => { :subdomain => /(www.)?api/ }

如果请求比这更复杂,那么事情变得棘手。那么有没有办法在用于约束的类中添加单个方法?

基本上,如何实现以下目标?它甚至可能吗?什么是使用白名单子域名的最佳方法?

E.g。

Class Subdomain

  def self.admin_constraint( request )
    # Some logic specifically for admin, possible calls to a shared method above.
    # We could check splits `request.subdomain.split(".")[ 1 ].blank?` to see if things are prefixed with "www" etc....
  end

  def self.api_constraint( request )
    # Some logic specifically for api, possibly calls to a shared method above.
    # We could check splits `request.subdomain.split(".")[ 1 ].blank?` to see if things are prefixed with "www" etc....
  end

  def self.matches?( request )
    # Catch for normal requests.
  end

end

我们现在可以通过以下方式特别调用约束:

:constraints => Subdomain.admin_constraints

所有通用约束如下:

:constraints => Subdomain

这在Rails 4.0.3中是否可行?

1 个答案:

答案 0 :(得分:0)

路由器将在您通过路由的任何对象上调用#matches?(request)方法。在

的情况下
:constraints => Subdomain

您正在为Subdomain Class对象提供路由。但是,您也可以传递一个实例,您可以通过参数进行配置。如,

Class Subdomain
  def initialize(pattern)
    @pattern = pattern
  end

  def matches?(request)
    request.subdomain.present? && @pattern ~= request.subdomain
  end
end

# routes.rb

namespace :admin, constraints: Subdomain.new(/(www.)?admin/) do
  # your admin routes here.
end

注意:我没有验证代码是否有效,我只是把它写在了我的头顶,所以考虑更多的伪代码而不是实现准备。

此外,您可以在Use custom Routing Constraints to limit access to Rails Routes via Warden查看此技术的示例,其中包含更多详细信息。