是否可以动态删除一定级别的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
的范围与原始块的范围相同)。