我一直试图弄清楚这个查询,我不知道如何得到它。
我有一个模型Book
class Book < ActiveRecord::Base
# Relationships
has_many :requests, dependent: :destroy
end
和此模型Request
class Request < ActiveRecord::Base
belongs_to :book
# Enumerables
enum status: [:pending, :accepted, :completed]
end
我想查询以获取图书:
:completed
我的2美分:
我设法将它们分开:
scope :without_requests, -> {
requested_books_ids = Request.pluck(:book_id)
where.not(id: requested_books_ids)
}
scope :with_requests_but_not_completed, -> {
includes(:requests).where.not(requests: {status: Request.statuses[:completed] })
}
但我没有任何成功加入结果。我试过这个:
@books = Book.without_requests + Book.with_requests_but_not_completed
@books = @books.paginate(page: params[:page], per_page: 2)
失败了
有什么建议吗?
更新
不确定是否相关...但我使用SQLite进行开发和测试,使用Postgresql进行生产。我听说最好有相同的系统,但这不应该改变查询的结果,不是吗?
答案 0 :(得分:1)
你的方法还不错。如果你想坚持下去,那么下面是什么:
Book.all
.eager_load(:requests)
.where([
"books.id not in (?) or requests.status <> ?",
Request.pluck(:book_id),
Request.statuses[:completed]
])
eager_load
基本上是您应该使用的includes(:requests)
+ references(:status)
。在这种情况下,你想要加入,所以我更喜欢使用预先加载,你可以查看这篇文章,它大大解释了what eager_load is
答案 1 :(得分:0)
这可以通过原始SQL轻松完成,但似乎您希望依赖ActiveRecord提供的DSL。
您需要OR
,但遗憾的是无法使用。{
您最好的选择是自己实施,例如使用此方法:
def join_with_or(*relations)
relations.map do |relation|
clause = relation.arel.where_sql.sub(%r{\AWHERE }, '')
"(#{clause})"
end.join(' OR ')
end
one = Book.where.not(id: Request.pluck(:book_id))
two = Book.joins(:requests).where.not(requests: { status: Request.statuses[:completed] })
Book.where(join_with_or(one, two))