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

Posted

技术标签:

【中文标题】如何毫无例外地选择Array Rails ActiveRecord中的ID【英文标题】:How to select where ID in Array Rails ActiveRecord without exception 【发布时间】:2010-11-29 07:59:02 【问题描述】:

当我有一个 id 数组时,比如

ids = [2,3,5]

我表演

Comment.find(ids)

一切正常。但是当有不存在的 id 时,我得到一个异常。这通常发生在我获得与某些过滤器匹配的 ID 列表并且比我执行类似的操作时

current_user.comments.find(ids)

这一次我可能有一个有效的评论 ID,但它不属于给定的用户,所以没有找到它,我得到一个异常。

我试过find(:all, ids),但它会返回所有记录。

我现在唯一能做到的就是

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

但在我看来,这似乎是一种超级低效的解决方案。

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

【问题讨论】:

【参考方案1】:

如果只是避免您担心的异常,“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])

【讨论】:

这是我的首选方案,看起来比异常处理路线更干净 作为另一个扩展,如果你需要链接复杂的条件,你甚至可以做 Comment.all(:conditions => ["approved and id in (?)", [1,2, 3]]) 这将在 Rails 4 中被弃用:edgeguides.rubyonrails.org/… @JonathanLin 是正确的,应该首选 mjnissim 的答案:***.com/a/11457025/33226 这将返回一个Array 而不是ActiveRecord::Relation,这限制了您之后可以使用它执行的操作。 Comment.where(id: [2, 3, 5]) 确实返回 ActiveRecord::Relation【参考方案2】:

更新:这个答案与 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 这叫什么,它是如何工作的?它是 Rails 的魔法吗?!正如一位同事评论的那样,这就像“将整数与对象列表进行比较”。【参考方案3】:

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

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

【讨论】:

正是我想要的。谢谢! 取回对象时有什么办法可以保持your_id_array 的顺序吗? @JoshPinter 我不认为这是期望数据库以相同顺序返回内容的可靠方法。也许在最后添加一个 ORDER BY 查询以确保事情的正确顺序。 @JonathanLin 感谢乔纳森的回复。你当然是对的。在我的情况下,使用ORDER BY 不起作用,因为订单不是基于属性的。但是,有一种方法可以通过 SQL 来完成(所以速度很快),甚至有人为它创建了一个 gem。看看这个问答:***.com/questions/801824/…【参考方案4】:

现在 .find 和 .find_by_id 方法在 rails 4 中已弃用。因此我们可以使用以下方法:

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

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

user.comments.where(id: avoided_ids_array)

也用于排除 ID

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

【讨论】:

github.com/rails/activerecord-deprecated_finders .find 和 .find_by_id 方法在 rails 4 中不被弃用。【参考方案5】:

为避免异常杀死您的应用,您应该捕获这些异常并按照您希望的方式处理它们,在未找到 id 的情况下为您的应用定义行为。

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

这里是 more info,关于 ruby​​ 中的异常。

【讨论】:

是的,这解决了问题,但它并不是一个真正干净的解决方案 如果你要捕获一个异常,你应该声明你希望捕获的异常,否则你可能会捕获一些你没有预料到的东西并隐藏一个实际的问题。【参考方案6】:

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

例如包括一些其他模型:

named_scope 'get_by_ids', lambda |ids| :include => [:cmets], :conditions => ["cmets.id IN (?)", ids]

【讨论】:

以上是关于如何毫无例外地选择Array Rails ActiveRecord中的ID的主要内容,如果未能解决你的问题,请参考以下文章

Rails的不同缓存策略

Rails 如何知道何时从 `sessions` 表中删除记录?

如何向 watson 对话响应添加操作?

rails .each 无缘无故地跳过第二个元素

在 Rails 上为连接、限制、选择等(不是条件)的 SQL 片段安全地转义字符串

如何在 .NET 中毫无例外地打印当前的堆栈跟踪?