在Ruby中的一个语句中更新具有不同值的多个记录

时间:2014-05-08 18:11:47

标签: sql ruby-on-rails ruby

使用Rails 4.不确定我是否过于雄心勃勃。我有以下示例:

params[:shop].each_with_index do |id, index|
  Shop.update(id, position: index + 1)
end

其中params[:shop] = [1, 3, 5, 7]shop个ID的列表。上面的代码应该触发4个单独的SQL,如下所示:

Shop Load (0.7ms)  SELECT  `shops`.* FROM `shops`  WHERE `shops`.`id` = 1 LIMIT 1
  (0.2ms)  BEGIN
SQL (0.5ms)  UPDATE `shops` SET `position` = 1 WHERE `shops`.`id` = 1
Shop Load (0.7ms)  SELECT  `shops`.* FROM `shops`  WHERE `shops`.`id` = 3 LIMIT 1
  (0.2ms)  BEGIN
SQL (0.5ms)  UPDATE `shops` SET `position` = 2 WHERE `shops`.`id` = 3
Shop Load (0.7ms)  SELECT  `shops`.* FROM `shops`  WHERE `shops`.`id` = 5 LIMIT 1
  (0.2ms)  BEGIN
SQL (0.5ms)  UPDATE `shops` SET `position` = 3 WHERE `shops`.`id` = 5
Shop Load (0.7ms)  SELECT  `shops`.* FROM `shops`  WHERE `shops`.`id` = 7 LIMIT 1
  (0.2ms)  BEGIN
SQL (0.5ms)  UPDATE `shops` SET `position` = 4 WHERE `shops`.`id` = 7

有没有办法将SQL缩减为一个语句?

2 个答案:

答案 0 :(得分:0)

那里有一个update_all,所以这不是你的问题。请参阅文档here

您可以执行以下操作:

shop_ids = [1,3,5,4]
Shop.where("id in (?)", company_ids).update_all(...)

更大的问题是你在update_all中放了什么,因为你是基于数组中shop_id的索引位置。如果你知道你只是想要上下颠倒所有这些 - 你当然可以像

那样做
shop_ids = [1,3,5,4]
Shop.where("id in (?)", company_ids).update_all("position = position + 1")

除此之外 - 你可能做的事情可能不多。

答案 1 :(得分:-1)

这是问题的答案,而是对我为什么不对params哈希执行操作的评论的扩展。

白名单简单地说允许某些属性。这样做的原因是为了防止用户属性插入到params中。假设您在帖子控制器上并将所有内容列入白名单,用户可以插入以下参数:

"user":"123", "password":"abc"

如果您只是使用params哈希更新您的模型,您可能只是覆盖了用户123的密码,现在就是' abc' - 一个巨大的安全漏洞。

如果您将params严格限制为Post模型上的属性,则会缩小用户可能造成伤害的范围。但是,减少损害的范围并不意味着预防。

在您提供的代码中,您假设id将是一个数字。如果它不是什么?这就是SQL注入成为问题的地方*。 See this page for examples。如果用户注入恶意SQL,他们可能会获得整个数据转储,包括敏感信息。如果您打算使用params,请小心。

其他资源:Ruby On Rails Security Guide

* Rails清理了很多数据,但有些部分留给sql注入,比如update_all