理解Rails中的约束

时间:2015-11-17 09:21:24

标签: ruby-on-rails ruby rspec

我一直在进行测试,以确保根据此资源声明,某些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

现在我的测试通过,但我不明白为什么,不能不理解它就离开它。所以我有两个问题

  1. 为什么测试在开始时失败了?
  2. 如何添加约束参数来修复它?

3 个答案:

答案 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是字符串。