2013-12-07 43 views
0

我有一个项目,其中客户端坚持所有内容URL都是顶级的。这包括跨越非常不同的资源类型的网址,例如:顶级URL的多种资源类型

/products  #=> The Category "products" 
/privacy  #=> A content-managed SystemPage "privacy" 
/foo-bar-baz #=> An Article "foo bar baz" (user generated, no less) 

Obiviously,这是有问题的,提高至少两个技术问题:

  1. 路由不能通过基于模式的办法来处理
  2. 这些不同的内容片段需要在表格中是唯一的。

这并不是说它认为Rails本身是对立的,并且肯定不符合框架的预期模式。

这就是说,我想知道是否有一个合理的理智的方式来实现这一点。

我的第一反应是维持“蛞蝓”,其映射蛞蝓如果以某种方式能够资源类型,并通过塞在站点根执行查找,然后,向前请求到合适的控制器的一个表。我即将研究这种可能性,但我想我应该看看是否有其他人解决了这个问题(除了解雇客户)。

回答

1

我想到转发从一个控制器到另一个控制器的请求是不正确的。在Rails 3+中,您可以直接转到Rack端点。实际上,控制器操作本身就是作为机架终端实现的。

因此,为了解决这个问题,我创建了一个简单的Rack应用程序,该应用程序查找给定slug的Permalink,该slug具有对不同资源类型之一的多态引用。然后控制器确定并将env传递给动作。基本上是路由器中的中间件层。

本质:

class PermalinkRouter 
    def call(env) 
    req = ActionDispatch::Request.new(env) 

    # will throw if not found 
    permalink = Permalink.find_by!(slug: req.params['id']) 

    # resource_controller is a method of permalink, which constantizes 
    # a controller based on its resource_type. 
    permalink.resource_controller.action(:show).call(env) 
    end 
end 

get "/:id", to: PermalinkRouter.new 

无论何时创建资源类型中的一种本身产生的永久链接,并处理建立独特的蛞蝓。

这超出了这个问题的范围,但以这种方式将链接看作自己的资源,这使我可以做一些其他有趣的事情,包括实现永久链接“历史”,其中旧链接生活在301重定向当前的资源URL。

+0

酷解决方案,让我思考! – DeeY

1

在routes.rb中,你可以

match '/*', :controller => proc { (lookup the db here) } 

How to pass params to a block in Rails routes?

另一种方法是,试图说服客户接受前缀的网址像/ category_products或/ article_foo_bar,这是很容易设置的导轨方式

+0

+1谢谢,这让我想到了,并让我记住,控制器的行为只是机架端点。但我不相信你*可以*传递一个proc到'controller'选项,至少不是在rails 4中。 – numbers1311407

+0

是的,你可以有:controller => proc {...}调用,但不幸的是,它似乎仅被评估一次并为随后的请求进行缓存。但我想应该可以重写这个。 – DeeY