【问题标题】:How to select where ID in Array Rails ActiveRecord without exception如何毫无例外地选择Array Rails ActiveRecord中的ID
【发布时间】: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 而不会在不存在的记录上出现异常?

【问题讨论】:

    标签: ruby-on-rails activerecord find


    【解决方案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 的答案:stackoverflow.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。看看这个问答:stackoverflow.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])
    

    【讨论】:

    【解决方案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] } }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-06
      相关资源
      最近更新 更多