我有一个项目,其中客户端坚持所有内容网址都是顶级的。这包括跨不同资源类型的URL,例如:
/products #=> The Category "products"
/privacy #=> A content-managed SystemPage "privacy"
/foo-bar-baz #=> An Article "foo bar baz" (user generated, no less)
很明显,这是有问题的,至少引发了两个技术问题:
这并不是说它与Rails本身相反,并且肯定与框架的预期模式不一致。
话虽如此,我想知道是否有合理的理由来实现这一目标。
我的第一直觉是维护一个“slugs”表,它将slug映射到资源类型并通过slug在站点根目录执行查找,然后,如果可能的话,将请求转发给相应的控制器。我即将研究这种可能性,但我想我应该看看是否有其他人有解决这个问题的方法(除了解雇客户端)。
答案 0 :(得分:1)
,你可以
match '/*', :controller => proc { (lookup the db here) }
请参阅How to pass params to a block in Rails routes?
另一种方法是尝试说服客户接受像/ category_products或/ article_foo_bar这样的前缀URL,这些URL很容易设置rails方式
答案 1 :(得分:1)
我想到转发从一个控制器到另一个控制器的请求是不正确的。在Rails 3+中,您可以开箱即用地路由到Rack端点。这实际上就是控制器操作本身的实现方式,如机架端点。
为了解决这个问题,我创建了一个简单的Rack应用程序,它为给定的slug查找Permalink
,它具有对不同资源类型之一的多态引用。然后确定控制器并将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
只要创建了一种资源类型,就会生成永久链接本身,并处理构建唯一的slug。
这超出了这个问题的范围,但是以这种方式将链接视为自己的资源使我能够做一些其他有趣的事情,包括实现永久链接“历史”,其中旧链接作为301重定向到当前资源网址。