是否可以动态删除Rails资源嵌套级别? [英] Is it possible to dynamically remove a level of rails resource nesting?

查看:64
本文介绍了是否可以动态删除Rails资源嵌套级别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要路由才能同时使用Rails应用程序的托管版本和whitelabel版本。这两个版本都在同一代码库和同一服务器上运行,因此路由需要弄清楚,但我不清楚如何实现此目标。



建立工作委员会。每个注册的公司都可以在网站上创建自己的公司资料。如果他们获得了付费的高级版,则可以使用自己的CNAME网址,并在其子域之一内为工作板提供服务。都是标准的东西。



主站点上的路线看起来像

  http://jobsrus.com/companies/公司名称
#例如
http://jobsrus.com/companies/microsoft

这会导致诸如

  http://jobsrus.com/companies/microsoft/jobs/ 
http://jobsrus.com/公司/微软/最新

在白标网站上需要显示什么样的路线



公司还可以给工作板贴上白色标签,使其看起来像这样:

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

澄清差异



为了澄清起见,相同的 controller#action 将由以下两者交付:

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

难看的路线:



最简单的路线是:



路线。 rb

 资源:公司要做
...
资源:工作要做
...
结束
结束

它给出:

  http://jobsrus.com/公司/微软/职位

#以及

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

我们希望后者为:

  http://jobs.microsoft.com/jobs 

如何删除此第一级是从路线嵌套吗?



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



routes.rb

 资源:工作完成
...
结束

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



------编辑(和部分解决方案)-----------------------



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



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

  def company_resources 
资源:仅工作:[:index,:show]做
资源:仅申请人: [:index,:show]做
资源:仅消息:[:index,:show]
结束
结束
结束

约束主机:/^(?!jobsrus\.com)/ do
company_resources
end

资源:companies,仅:[:index,:show]做
company_resources
end

这在匹配传入请求方面效果很好,我们可以看到耙路产生我们要寻找的匹配项:

  job_applicants_messages GET / jobs /:job_id / applicants / messages(。:format){:host => / ^(?! jobsrus\.com)/,:action => show,:controller => messages} 
job_appli cants GET /jobs/:job_id/applicants(.:format){:host => / ^(?! jobsrus\.com)/,:action => show,:controller => applicants }
个工作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}
公司GET /companies(.:format){ :action => index,:controller => companies}
公司GET /companies/:id(.:format){:action => show,:controller =>公司}

但是,现在不再有任何规范的路线生成方法。如果要创建通往特定公司的工作指数的路线,则必须使用不同的方法,具体取决于我们是在白标公司上还是在 jobsrus.com 公司上:

 #白色标签公司上的工作页面的路径生成器
jobs_path
#=> ‘microsoft.com/jobs’

#主站点上公司上的作业页面的路径生成器
company_jobs_path @company
#=> ‘jobsrus.com/companies/microsoft/jobs’

#实际需要的内容
company_jobs_path @company
#=> ‘jobsrus.com/companies/microsoft/jobs’(在主站点上)
#=> 'microsoft.com/jobs'(在whitelabel上时)

我可以覆盖路径方法并定义一些取决于 host 变量的方法。不过,最好采用 rails方式进行此操作。

解决方案

有趣的问题。我认为使用基于请求的约束可以实现此目的。



在初始值设定项中,定义一个常量:

  YOUR_HOST =' jobsrus.com'.freeze 

然后在route.rb中:

 约束:host => /!#{YOUR_HOST} /做
资源:工作
结束

资源:公司做
资源:工作
结束

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



但是现在,您需要对控制器进行更改,因此可以检索公司并相应地分配职位资源(没有尝试过,请谨慎使用):

  class JobsController< ApplicationController 
before_filter:resolve_whitelabel

def resolve_whitelabel
如果request.host!= YOUR_HOST
#不安全,仅演示
@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
结束

def index
#只是一个例子
@jobs = scoped_jobs .recent
结束
结束

您只需要记住始终要使用 scoped_jobs



编辑



您可以将块存储在过程

  routes = Proc.new do 
资源:工作
结束

...,然后您应该可以使用& Proc 转换回一个块c $ c>运算符:

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

这需要测试,我从未使用过在这种情况下。尤其要注意, Proc 充当闭包:它捕获其上下文(在此范围内可用的变量,等等。这称为绑定)。被创建(就像块一样)。这可能会导致意外行为(尽管我认为在这种情况下这无关紧要,因为您的 Proc 的范围与原始块的范围相同)。 / p>

I need routing to work for both a hosted and whitelabel version of a rails app. Both versions are running off the same codebase and on the same server so the routing needs to figure things out but it's not clear to me how to achieve this.

I'm building a job board. Each company signing up can create their own company profile on the site. If they get a paid premium version they can use their own CNAME'd URL and serve the job board off one of their subdomains. All pretty standard stuff.

What routes need to look like on the main site

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

which leads to routes such as

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

What routes need to look like on the whitelabel sites

The company can also whitelabel the job board so that it looks like this:

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

Clarifying the difference

Just to clarify, the same controller#action will be delivered by both:

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

Ugly routing:

The simplest routing is:

routes.rb

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

which gives:

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

# but also

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

Whereas we want the latter to be:

http://jobs.microsoft.com/jobs

How to drop this first level of nesting from the route?

My question is very straightforward. How do I drop the companies/company-name nesting level from the route? The only routing necessary for the white label site is:

routes.rb

resources :jobs do
  ...
end

How can I dynamically include or exclude a level of nesting from the routing? I can use the request.host variable to trigger the switch but I don't know how best to either activate or de-activate that layer of nesting.

------ EDIT (and partial solution) -----------------------

Using @m_x's answer I've used constraints to create the routing. In order to better illustrate the problem I've also used a couple of extra routes:

(simplified to just display the :show and :index methods)

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

This works well in terms of matching incoming requests, we can see that rake routes produces the matches we're looking for:

        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"}

However, there are now no longer any canonical methods for producing the routes. If we want to create a route to a particular company's job index we have to use a different method depending on whether we're on a whitelabel company or on a jobsrus.com company:

# 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)

I could override the path methods and define some methods that switch depending on the host variable. It would be nice to do this the rails way though. Is this supported?

解决方案

interesting question. i think it might be possible to do this using request-based constraints.

in an initializer, define a constant :

 YOUR_HOST = 'jobsrus.com'.freeze

then in routes.rb :

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

 resources :companies do
   resources :jobs
 end

the order here is important : if request.host does not match your host name, the first set of routes is available and captures the request before it hits the second set.

but now, you will need to make changes to your controller, so that it can retrieve the company and scope the jobs resources accordingly ( didnt try this, use with caution ):

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 

you just have to remember always to use the scoped_jobs.

Edit

You can "store" a block in a Proc :

routes = Proc.new do
           resources :jobs
         end

... and then you should be able to convert back this Proc into a block using the & operator :

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

this needs to be tested, i never used it in this context. Be aware, in particular, that a Proc acts as a closure : it captures its context (variables available in this scope, etc. This is called its 'binding') when it is created (much as a block does). This may lead to unexpected behaviour (though i don't think it will matter in that case, because your Proc's scope is the same as the original block's one).

这篇关于是否可以动态删除Rails资源嵌套级别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆