ChatGPT解决这个技术问题 Extra ChatGPT

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

当我有一组 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 而不会在不存在的记录上出现异常?


S
Snowman

如果只是避免您担心的异常,则“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 的答案:stackoverflow.com/a/11457025/33226
这将返回 Array 而不是 ActiveRecord::Relation,这限制了您之后可以使用它执行的操作。 Comment.where(id: [2, 3, 5]) 确实返回 ActiveRecord::Relation
m
mjnissim

更新:这个答案与 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 的魔法吗?!正如一位同事评论的那样,这就像“将整数与对象列表进行比较”。
J
Joshua Pinter

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

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。查看此问答:stackoverflow.com/questions/801824/…
S
Sumit Munot

现在 .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 中不被弃用。
r
rogeriopvl

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

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

下面是关于 ruby 异常的 more info


是的,这解决了问题,但这并不是一个真正干净的解决方案
如果你要捕捉一个异常,你应该声明你期望捕捉的异常,否则你可能会捕捉到你没有预料到的东西并隐藏一个实际的问题。
m
mtfk

如果您想在其中添加其他条件,也可以在 named_scope 中使用它

例如包括一些其他模型:

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