减去两个ActiveRecord :: Relation对象

时间:2017-06-29 12:34:18

标签: ruby-on-rails postgresql activerecord relationship

我想让我的应用程序的用户有机会从他们的微博中删除不需要的微博。默认情况下,微博的提要由用户自己的微博加上来自用户的微博组成:

def feed
  following_ids = "SELECT followed_id FROM relationships
                   WHERE  follower_id = :user_id"
  Micropost.where("user_id IN (#{following_ids})
                   OR user_id = :user_id", user_id: id)
end

我创建了一个Quarantine模型,其中用户和不需要的微博相关联。然后我找了一个ActiveRecord::Relation方法,允许我从上面where中减去以下where

microposts_ids = "SELECT micropost_id FROM quarantines
                  WHERE  user_id = :user_id"

Micropost.where("micropost_id IN (#{microposts_ids})", user_id: id)

我找不到与-数组运算符对应的任何方法。但是我在Stackoverflow问题中找到了方法mergeCombine two ActiveRecord::Relation objects,据我所知,这将允许我将wheres链接如下:

Micropost.where("user_id IN (#{following_ids}) OR user_id = :user_id", user_id: id).merge(Micropost.where.not("micropost_id IN (#{microposts_ids})", user_id: id))

不同之处在于我将第二个where更改为where.not
此解决方案的问题是where.not将加载未隔离的所有Micropost,这对于数据库来说比仅加载隔离的微博更重要。是否有merge方法的替代解决方案,例如从原始Feed中减去隔离的微博的方法?

2 个答案:

答案 0 :(得分:2)

对于特定的user

microsposts_not_to_show = Micropost.joins(:quarantines).where("quarantines.user_id" => user.id)
all_microposts = Micropost.where("user_id" => user.id) + Micropost.joins(:user => : relationships).where("relationships.follower_id" => user.id)
microposts_to_show = all_microposts - microposts_not_to_show

答案 1 :(得分:0)

对于Rails 5,它可能看起来像:

class User < ApplicationRecord
  has_many :relationships
  # ...
  def feed
    Micropost
      .where(user_id: relationships.select(:followed_id))
      .or(Micropost.where(user_id: id))
      .where.not(id: Quarantine.select(:micropost_id).where(user_id: id))
  end
end

feed返回relation,它会产生一个数据库请求,并且可以通过额外的过滤,排序链接 - 无论您需要什么。