我一直在进行测试,以确保根据此资源声明,某些CRUD操作在我的应用程序中无法路由
resources :posts, only: [:index, :show] do
resources :categories
end
我的Rspec控制器测试
it 'does not route to #new' do
expect(get: '/posts/new').to_not be_routable
end
当我运行此测试时,我得到以下输出
expected {:get=>"/posts/new"} not to be routable, but it routes to {:controller=>"posts", :action=>"show", :id=>"new"}
因此经过一些研究后,我在SO上发表this帖子,读过它是使用约束来实现解决方案。
resources :posts, only: [:index, :show], except: :new, constraints: { id: /\d+/ } do
resources :categories
end
现在我的测试通过,但我不明白为什么,不能不理解它就离开它。所以我有两个问题
答案 0 :(得分:3)
根据您关联的帖子以及您实施的答案,
之间的区别
'/posts/new' # which is the route to the new action of post controller
和
'/posts/:id' #which is the route to the show action of the same controller
几乎没有,除了一个是/new
而另一个是/:id
现在,这种差异几乎没有,因为拥有像/posts/:id
这样的路线意味着这里唯一真正需要的是/posts/
部分。在此之前的任何其他内容都将被视为id
的{{1}}。
为此,/posts/:id
,/posts/5
,/posts/10
,/posts/you
,甚至/posts/me
都匹配/posts/new
。与/posts/:id
等于=> 5,10,你,我,新人。
以上是您的测试失败的原因,因为:id
可以路由到show动作,基本上是/posts/new
另一方面,当您添加约束(id:/ \ d + /)时,您告诉/posts/:id
应该是严格数字的路由。这将防止任何非数字的字符被解释为id
,因此,从上面的示例中,(id
,/posts/5
,/posts/10
,{{1 }},甚至/posts/you
),只有/posts/me
和/posts/new
会与show动作匹配,而其他动作则不会。
希望这很好解释......
答案 1 :(得分:1)
1)由于:show
的{{1}}路由,您的测试最初失败了。它看起来像这样:
:posts
这将匹配任何GET /posts/:id(.:format) posts/#show
请求到/ posts / xxxx,并将您在路径的第二部分(在本例中为GET
)中放置的任何内容分配给{{{}中的:id元素1}}哈希。
如果您在浏览xxxx
后检查params
操作中的params[:id]
值,则会看到show
为什么你的测试失败了?
在您的测试中,您正在检查/posts/new
是否在任何地方都没有路由。但是对params[:id] == 'new'
的可接受值没有任何限制,它将路由到您的show动作。
2)您添加的约束指定/posts/new
参数必须与正则表达式:id
匹配才能被接受。这是一个或多个数字(0-9)。
因此,:id
被接受,但/\d+/
不被接受。顺便提一句,此约束将禁止您使用友好ID来使您的网址更好。例如GET /posts/123
是不可接受的,因为约束指定任何参数都是整数。
答案 2 :(得分:1)
好吧,这就是我认为发生的事情。
如果您放回原始代码:
GET /posts/new
并运行GET /posts/my-new-post-about-something
,您会看到resources :posts, only: [:index, :show] do
resources :categories
end
可以与rake routes
路线之一匹配,get posts/new
匹配字符串"新"
添加id必须为数字的约束不允许再次发生此匹配。
请注意,如果你使用的是mongoid而不是activerecord,那么你的约束就不会起作用,因为ids是字符串。