【问题标题】:Find records with no has_many :through record matching criteria查找没有 has_many 的记录:通过记录匹配条件
【发布时间】:2016-11-13 08:27:05
【问题描述】:

使用 Rails 4,并给出以下模型:

class Draft < ActiveRecord::Base
  has_many :drafters
  has_many :users, through: :drafters
end

class Drafter < ActiveRecord::Base
  belongs_to :draft
  belongs_to :user
end

class User < ActiveRecord::Base
  has_many :drafters
  has_many :drafts, through: :drafters
end

如何检索与用户实例current_user 无关的所有草稿?即所有草稿d,其中没有属于dcurrent_user 的Drafter。

如果有帮助,我有 Squeel 可用。

【问题讨论】:

    标签: ruby-on-rails activerecord rails-activerecord has-many-through


    【解决方案1】:
    Draft.includes(:drafters).where(:drafters => { :draft_id => nil } ) 
    

    将返回所有没有起草者的草稿。

    Draft.includes(:drafters).where.not(:drafter => { user_id => current_user.od })
    

    将返回所有不属于 current_user 的草稿。

    更多详情请关注the difference between outer an inner join

    【讨论】:

      【解决方案2】:

      你可以用includes实现它:

      Draft.includes(:drafters)
           .where('(drafters.user_id <> ? or drafters.user_id is null)', current_user.id})
           .references(:drafters)
      

      【讨论】:

      • 这不太行。首先,它根本找不到那些有 no 起草人的草稿。其次,使用它会产生弃用:DEPRECATION WARNING: It looks like you are eager loading table(s) (one of: drafts, drafters) that are referenced in a string SQL snippet. - full text here
      • @Chowlett:已更新。 references 删除弃用警告(即强制 left join),而 is null 检查允许没有起草人的草稿。
      • 呃,哇。这比我预期的要丑陋得多。为什么它有效?生成的 SQL 是 DraftDrafter 上的 LEFT OUTER JOIN,因此应该在 Drafter 侧不存在的地方出现行。为什么我需要drafters.user_id is null 来提取drafter.draft_id 上没有Drafter 行匹配的情况?
      • ...不,将其更改为Draft.joins... 又回到了缺少草稿而根本没有草稿人的问题。
      • 在psql里摸索,我现在明白了原因。首先,WHERE 不影响 JOIN,它只是过滤结果。第二个 NULL 总是比较假。也就是说,(NULL 1) 为假。谢谢!
      【解决方案3】:

      使用 Squeel,您可以:

      Draft.joins{drafters.outer}.where{(drafters.user_id != current_user.id) | (drafters.user_id.eq nil)}
      

      将生成:

      SELECT "drafts".* FROM "drafts" LEFT OUTER JOIN "drafters" ON "drafters"."draft_id" = "drafts"."id" WHERE ("drafters"."user_id" != 1 OR "drafters"."user_id" IS NULL)
      

      【讨论】:

      • 我试过这个,但最后发现它返回了多个草稿,其中有多个 non-current_user Drafters。 includes 方法似乎是唯一可行的方法。
      【解决方案4】:

      我根据以下嵌套查询找到了答案(使用 squeel):

      SELECT "drafts"."id" FROM "drafts"
          WHERE "drafts"."id" NOT IN 
              (SELECT "drafters"."draft_id" FROM "drafters" 
                  WHERE (("drafters"."draft_id" = "drafters"."id" 
                          AND "drafters"."user_id" = 2)))
      

      这可以转换为 Rails+squeel 查询:

      Draft.where{ id.not_in(Drafter.select(:draft_id).where{
              (draft_id == drafts.id) & (user_id == omit_user_id)})}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-04-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多