update_attributes()与update_all()&在删除的对象上

时间:2014-05-15 11:20:55

标签: ruby-on-rails ruby attributes

我试图更新对象的属性,但我尝试更新的对象通常不再存在。

例如:我正在处理CSV文件以获取属性:

array.each do |a|
  player = Player.find_by_grepo_id(a[:grepo_id])
  player.update_attributes(a)
end

如果找不到播放器,则会抛出错误。

我从之前的经历中学到了什么:

  

ActiveRecord :: Base.find如果找不到记录则总是抛出异常,这是故意的。   我应该只使用find,如果我绝对希望拥有我正在寻找的任何东西。   如果我发布了一个节目动作并且无法找到该文章,我应该挽救该异常并呈现404(未找到)   而不是重定向到索引(技术上)。

     

如果我想在没有强制异常的情况下通过它的id属性找到某些东西,我应该使用动态查找器   find_by_id(在我的情况下是find_by_grepo_id),如果找不到具有该id的记录,将返回false。

但是在运行包含上述代码的任务时我得到了

NoMethodError: undefined method `update_attributes' for nil:NilClass

那是因为具有该特定ID的玩家不再存在。如果我用update_attributes方法将.present?调用包装起来就可以了。

我缺少什么?不应该使用find_by_id方法不抛出错误而只是跳过它吗?

3 个答案:

答案 0 :(得分:3)

如果你想在一个电话而不是两个电话中进行,你可以使用这样的update_all方法:

Player.where(:grepo_id => a[:grepo_id]).update_all(a)

这将产生以下SQL:

UPDATE players SET ... = ..., ... = ... WHERE players.grepo_id = ...

如果grepo_id不存在,也可以使用:任何内容都不会更新。但请注意,这只是运行SQL; 忽略模型上的任何验证或回调

答案 1 :(得分:2)

这是因为你正在执行update_attributes,即使它没有通过grepo_id找到记录。如果找不到任何记录,find_by_grepo_id将返回nil。所以你需要添加一个条件来摆脱这个错误。

array.each do |a|
  player = Player.find_by_grepo_id(a[:grepo_id])
  player.update_attributes(a) if player.present?
end

答案 2 :(得分:0)

Rails有一个try方法(check the docs),你可以在这里使用它:

array.each do |a|
  player = Player.find_by_grepo_id(a[:grepo_id])
  player.try do |p|
   p.update_attributes(a)
  end
end

当没有找到记录时,这应该可以正常工作并更新属性或无声地失败(不会抛出异常)。