如何将两个范围与OR组合

Vla*_*lad 23 database-design ruby-on-rails ruby-on-rails-3 rails-activerecord

我有一个标签Feed和一个朋友Feed.我想结合这两个并构建最终的"全部"提要.

对于朋友饲料:

class Post < ActiveRecord::Base
  scope :friendfeed, lambda{|x| followed_by}

  def self.followed_by(user)
    where("user_id IN (?) OR user_id = ?", user.watched_ids, user.id)
  end
end
Run Code Online (Sandbox Code Playgroud)

对于标签Feed:

class Post < ActiveRecord::Base
  scope :tagfeed, lambda{|x| infatuated_with}

  def self.infatuated_with(user)
    joins(:attachments).where("attachments.tag_id IN (?)", user.tags).select("DISTINCT pages.*")
  end
end
Run Code Online (Sandbox Code Playgroud)

我会从控制器中调用这样的东西(我使用Kaminari宝石进行分页):

@tag_feed = Post.tagfeed(current_user).page(params[:page]).per(21)
@friend_feed = Post.friendfeed(current_user).page(params[:page]).per(21)
Run Code Online (Sandbox Code Playgroud)

现在我想要一个通用的饲料,但我迷路了.范围用于缩小范围,但在这种情况下,我正在尝试进行OR操作.做像这样的事情

@mother_of_all_feed = @tag_feed + @friend_feed
Run Code Online (Sandbox Code Playgroud)

将是多余的,我将无法控制出现在单个页面上的帖子数量.我该怎么做呢?谢谢!

顺便说一句,对于标签我有这样的关联设置:

class Post < ActiveRecord::Base
  has_many :attachments
  has_many :tags, :through => :attachments
end

class Tag < ActiveRecord::Base
  has_many :attachments
  has_many :posts, :through => :attachments
end

class Attachment < ActiveRecord::Base
  belongs_to :tag
  belongs_to :post
end
Run Code Online (Sandbox Code Playgroud)

kei*_*ley 17

这个功能有一个rails pull请求(https://github.com/rails/rails/pull/9052),但与此同时,有人创建了一个猴子补丁,你可以将其包含在你的初始化程序中,这将允许你或范围和一个查询中的where子句仍然给你一个ActiveRecord::Relation:

https://gist.github.com/j-mcnally/250eaaceef234dd8971b

有了这个,你就可以像这样对你的范围进行OR操作

Post.tagfeed(current_user).or.friendfeed(current_user)
Run Code Online (Sandbox Code Playgroud)

或写一个新的范围

scope :mother_of_all_feed, lambda{|user| tagfeed(user).or.friendfeed(user)}
Run Code Online (Sandbox Code Playgroud)

  • OR将添加到Rails 5.0:https://github.com/rails/rails/pull/16052 (3认同)
  • 是的,“OR”已添加到 Rails 5 中的“ActiveRecord::Relation#or” - http://nithinbekal.com/posts/rails-5-features/ (2认同)

Vla*_*lad 4

回答我自己的问题。我想我找到了办法。

where("pages.id IN (?) OR pages.id IN (?)",
  Page.where(
      "user_id IN (?) OR user_id = ?",
      user.watched_ids, user.id
  ),
  Page
    .joins(:attachments)
    .where("attachments.tag_id IN (?)", user.tags)
    .select("DISTINCT pages.*")
)
Run Code Online (Sandbox Code Playgroud)

到目前为止似乎有效,希望就是这样!

  • 您对它的表现满意吗?看起来您在这里收到了 4-5 个查询。看来你有两个选择:编写原始 SQL 查询或使用我最喜欢的 gem squeel。它允许执行 OR 并支持导致嵌套 SQL 查询的“in”功能。看一下:https://github.com/ernie/squeel。我尝试“宣传”它几次,例如这里:http://stackoverflow.com/a/10551561/1322562,但只有很少人喜欢它。我想知道为什么。使用 squeel,您可以重用范围并在纯 Ruby 中构建复杂的查询,例如:通过单个(!!!) SQL 查询“Product.where{(id.in Product.ruby)|(id.in Product.rails)}” ! (7认同)