如何毫无例外地选择Array Rails ActiveRecord中的ID


134

当我有一组ID时,例如

ids = [2,3,5]

我表演

Comment.find(ids)

一切正常。但是,当有不存在的ID时,我会得到一个例外。通常,当我获得与某个过滤器匹配的ID列表时,会发生类似的情况

current_user.comments.find(ids)

这次我可能有一个有效的注释ID,但是该注释ID不属于给定的User,因此找不到该注释,并且出现异常。

我已经尝试过了find(:all, ids),但是它返回了所有记录。

我现在能做的唯一方法是

current_user.comments.select { |c| ids.include?(c.id) }

但这对我来说似乎是超级无效的解决方案。

有没有更好的方法来选择数组中的ID,而不会在不存在的记录上获得异常?

Answers:


215

如果只是避免您担心的异常,则“ find_all_by ..”函数系列可以正常工作而不会引发异常。

Comment.find_all_by_id([2, 3, 5])

即使某些ID不存在也可以使用。这适用于

user.comments.find_all_by_id(potentially_nonexistent_ids)

情况也是如此。

更新:Rails 4

Comment.where(id: [2, 3, 5])

这是我的首选解决方案,它似乎比异常处理方法还干净
Sam Saffron

5
作为对此的另一种扩展,如果您需要链接复杂的条件,甚至可以执行Comment.all(:conditions => [[“ approved and id in(?)”,[1,2,3]])
Omar Qureshi

14
:这会在导轨4被废弃edgeguides.rubyonrails.org/...
乔纳森·林

3
@JonathanLin是正确的,应该首选mjnissim的答案:stackoverflow.com/a/11457025/33226
Gavin Miller

6
这将返回一个,Array而不是ActiveRecord::Relation,这将限制您以后可以执行的操作。Comment.where(id: [2, 3, 5])确实返回ActiveRecord::Relation
约书亚·品特

147

更新:此答案与Rails 4.x更相关

做这个:

current_user.comments.where(:id=>[123,"456","Michael Jackson"])

这种方法的优势在于它返回一个Relation对象,您可以在该对象上加入更多的.where子句,.limit子句等,这非常有帮助。它还允许不存在的ID而不会引发异常。

较新的Ruby语法为:

current_user.comments.where(id: [123, "456", "Michael Jackson"])

感谢您where在与数组比较时确认语法。我以为可能必须用一条IN语句对SQL进行编码,但这看起来更干净,并且很容易替代已弃用的scoped_by_id
Mark Berry 2015年

1
这叫什么,它如何工作?这是Rails的魔法吗?作为同事评价说,它像“与对象列表”比较的整数。
ATW

22

如果需要更多控制(也许需要声明表名),则还可以执行以下操作:

Model.joins(:another_model_table_name)
  .where('another_model_table_name.id IN (?)', your_id_array)

正是我想要的。谢谢!
Myxtic

your_id_array取回对象时,有什么方法可以保持的顺序?
约书亚·品特

@JoshPinter我认为这不是期望数据库以相同顺序返回事物的可靠方法。也许在最后添加一个ORDER BY查询,以确保事物的正确顺序。
乔纳森·林

@JonathanLin感谢您的答复。你当然是对的。使用一个ORDER BY因为订单不是基于属性不会在我的情况下工作。但是,有一种方法可以通过SQL来做到这一点(因此非常快),甚至有人为此创建了一个gem。看看这个Q&A:stackoverflow.com/questions/801824/...
约书亚品特

10

现在,在rails 4中不推荐使用.find和.find_by_id方法。因此,我们可以使用以下方法:

Comment.where(id: [2, 3, 5])

即使某些ID不存在,它也将起作用。这适用于

user.comments.where(id: avoided_ids_array)

也用于排除ID

Comment.where.not(id: [2, 3, 5])

3
github.com/rails/activerecord-deprecated_finders .find和.find_by_id方法不是在铁轨已弃用4
美人蕉

0

为避免异常杀死您的应用程序,您应该捕获这些异常并按照您希望的方式对待它们,在找不到ID的情况下为您的应用程序定义行为。

begin
  current_user.comments.find(ids)
rescue
  #do something in case of exception found
end

这是有关ruby中异常的更多信息


1
是的,这可以解决问题,但这并不是真正的解决方案
Jakub Arnold

3
如果要捕获异常,则应声明您希望捕获的异常,否则,您可能会冒着捕获预期之外的风险并隐藏实际问题的风险。
海金2014年

0

如果要放置其他条件,也可以在named_scope中使用它

例如,包括一些其他模型:

named_scope'get_by_ids',lambda {| ids | {:include => [:comments],:conditions => [“” comments.id IN(?)“,ids]}}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.