rails rspec update_all方法在控制器中工作,但在rspec中不起作用

时间:2014-06-23 00:08:24

标签: ruby-on-rails rspec

**控制器

puts merchants.first.is_blocked // 1

Merchant.update_all( {:is_blocked => 0}, "mch_id IN (#{@merchants.map(&:mch_id).join(",")})" )

puts merchants.first.is_blocked // 0, so it works

** rspec

expect {
  get :update_merchants, params
}.to change { merchant_1.is_blocked }.from(1).to(0)

// result should have been changed to 0, but is now 1

我不知道为什么" update_all"方法在控制器中工作,并且在rspec中不起作用

2 个答案:

答案 0 :(得分:4)

首先,你的update_all行非常讨厌。假设@merchants是一个AREL查询,其中包含查找要更新的商家所需的条件,请考虑将其转换为:

@merchants.update_all(is_blocked: 0)

如果@merchants只是一个记录数组,那么请使用:

Merchant.where(id: @merchants.map(&:id)).update_all(is_blocked: 0)

其次,GET请求从不修改数据库。请考虑将此更改为PUT请求。

最后,如果在调用方法之前创建/获取了merchant_1实例变量,则测试仍具有预更改值。您需要重新获取它,或者在您看到更新的值之前在其上调用reload

expect {
  get :update_merchants, params
}.to change { merchant_1.reload.is_blocked }.from(1).to(0)

答案 1 :(得分:1)

您更新所有商家的is_blocked属性的电话应如下所示:

Merchant.where(id: @merchants.map(&:id)).update_all(is_blocked: 0)

要在@ Jon的答案评论中回答您的问题(关于update_allupdate_attributes之间的区别):

  • update_all将直接在数据库中运行一个SQL查询来更新数据。
  • update_attributes为每个运行它的对象实例运行一个SQL查询。

也就是说,update_all使用它时效率更高,因为数据库可以完成所有工作,并且擅长大规模UPDATE操作(不像循环遍历Ruby数组并运行)每条记录的单独SQL查询。)

然后,您需要确保在规范中重新加载merchant_1以破坏该对象上的Rails的请求级查询缓存:

expect {
  get :update_merchants, params
}.to change { merchant_1.reload.is_blocked }.from(1).to(0)