是否可以动态删除一定级别的rails资源嵌套?

我需要路由才能为rails app的托管和whitelabel版本工作。 这两个版本都运行在相同的代码库和同一服务器上,因此路由需要解决问题,但我不清楚如何实现这一点。

我正在建立一个工作委员会。 每个注册的公司都可以在网站上创建自己的公司资料。 如果他们获得付费高级版本,他们可以使用自己的CNAMEurl,并在其子域之一上提供工作板。 所有非常标准的东西。

在主站点上需要看什么路线

http://jobsrus.com/companies/company-name # eg http://jobsrus.com/companies/microsoft 

这导致了诸如的路线

 http://jobsrus.com/companies/microsoft/jobs/ http://jobsrus.com/companies/microsoft/newest 

在whitelabel网站上需要看什么路线

该公司还可以将作业板白色标记,使其看起来像这样:

 http://jobs.microsoft.com/jobs http://jobs.microsoft.com/newest 

澄清差异

为了澄清,同样的controller#action将由两者提供:

 http://company-domain/jobs # and http://jobsrus.com/companies/company-name/jobs 

丑陋的路由:

最简单的路由是:

的routes.rb

 resources :companies do ... resources :jobs do ... end end 

这使:

 http://jobsrus.com/companies/microsoft/jobs # but also http://jobs.microsoft.com/companies/microsoft/jobs 

而我们希望后者是:

 http://jobs.microsoft.com/jobs 

如何从路线中删除第一级嵌套?

我的问题很简单。 如何从路线中删除companies/company-name嵌套级别? 白标网站唯一需要的路由是:

的routes.rb

 resources :jobs do ... end 

如何从路由中动态包含或排除嵌套级别? 我可以使用request.host变量来触发切换但我不知道如何最好地激活或取消激活该嵌套层。

——编辑(和部分解决方案)———————–

使用@ m_x的答案我使用约束来创建路由。 为了更好地说明问题,我还使用了一些额外的路线:

(简化为只显示:show和:index方法)

 def company_resources resources :jobs, only: [:index, :show] do resource :applicants, only: [:index, :show] do resource :messages, only: [:index, :show] end end end constraints host: /^(?!jobsrus\.com)/ do company_resources end resources :companies, only: [:index, :show] do company_resources end 

这在匹配传入请求方面效果很好,我们可以看到rake routes产生了我们正在寻找的匹配:

  job_applicants_messages GET /jobs/:job_id/applicants/messages(.:format) {:host=>/^(?!jobsrus\.com)/, :action=>"show", :controller=>"messages"} job_applicants GET /jobs/:job_id/applicants(.:format) {:host=>/^(?!jobsrus\.com)/, :action=>"show", :controller=>"applicants"} jobs GET /jobs(.:format) {:host=>/^(?!jobsrus\.com)/, :action=>"index", :controller=>"jobs"} job GET /jobs/:id(.:format) {:host=>/^(?!jobsrus\.com)/, :action=>"show", :controller=>"jobs"} company_job_applicants_messages GET /companies/:company_id/jobs/:job_id/applicants/messages(.:format) {:action=>"show", :controller=>"messages"} company_job_applicants GET /companies/:company_id/jobs/:job_id/applicants(.:format) {:action=>"show", :controller=>"applicants"} company_jobs GET /companies/:company_id/jobs(.:format) {:action=>"index", :controller=>"jobs"} company_job GET /companies/:company_id/jobs/:id(.:format) {:action=>"show", :controller=>"jobs"} companies GET /companies(.:format) {:action=>"index", :controller=>"companies"} company GET /companies/:id(.:format) {:action=>"show", :controller=>"companies"} 

但是,现在不再有任何用于生成路线的规范方法。 如果我们想要创建一个到特定公司的工作指数的路线,我们必须使用不同的方法,这取决于我们是在whitelabel公司还是在jobsrus.com公司:

 # path generator for jobs page on a whitelabel company jobs_path # => 'microsoft.com/jobs' # path generator for jobs page on a company on the main site company_jobs_path @company # => 'jobsrus.com/companies/microsoft/jobs' # what is actually required company_jobs_path @company # => 'jobsrus.com/companies/microsoft/jobs' (when on main site) # => 'microsoft.com/jobs' (when on whitelabel) 

我可以覆盖路径方法并定义一些根据host变量切换的方法。 尽管如此,这样做很棒。 这支持吗?

有趣的问题。 我认为可以使用基于请求的约束来做到这一点。

在初始化程序中,定义一个常量:

  YOUR_HOST = 'jobsrus.com'.freeze 

然后在routes.rb中:

  constraints :host => /!#{YOUR_HOST}/ do resources :jobs end resources :companies do resources :jobs end 

此处的顺序很重要:如果request.host与您的主机名不匹配,则第一组路由可用,并在请求到达第二组之前捕获该请求。

但是现在,您需要对控制器进行更改,以便它可以检索公司并相应地调整作业资源的范围(没有尝试过,请谨慎使用):

 class JobsController < ApplicationController before_filter :resolve_whitelabel def resolve_whitelabel if request.host != YOUR_HOST # not safe as is, just demonstrates the idea @client = Company.find_by_host( request.host ) @scoped_jobs = Job.where( company_id: @client.id ) else @scoped_jobs = Job end end def scoped_jobs @scoped_jobs end def index # just an example @jobs = scoped_jobs.recent end end 

你只需记住总是使用scoped_jobs

编辑

您可以在Proc中 “存储”块:

 routes = Proc.new do resources :jobs end 

...然后你应该能够使用&运算符将这个Proc转换回一个块:

 constraints( :host => /!#{YOUR_HOST}/, &routes ) resources( :companies, &routes ) 

这需要进行测试,我从未在这种情况下使用它。 特别要注意, Proc充当闭包:它在创建时捕获其上下文(此范围中可用的变量等,这称为'绑定')(就像块一样)。 这可能会导致意外行为(虽然我认为在这种情况下它不重要,因为你的Proc的范围与原始块的范围相同)。