2015-02-08 79 views
0

當前如果你想添加一個約束,有許多方法可以做到這一點,但正如我目前所看到的,你只能包含一個被調用的權威方法。例如。Rails路由更復雜:約束

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前綴的路由問題,那就是管理和www.admin是indistuingishable。可以添加更多邏輯,但是如果需要通過一組靜態子域名(例如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?

回答

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