我有一个Fact
模型,has_many
:votes
。投票也有一个user_id
字段。
我想在Fact
模型的范围内表达以下内容:给我所有0票,user_id
等于X的事实。
我对Arel不太熟悉,无法理解如何解决这个问题。想法?
答案 0 :(得分:1)
这有效:
class Fact < ActiveRecord::Base
scope :by_user, lambda { |id| joins(:user).where('users.id == ?', id).readonly(false) }
scope :vote_count, lambda { |count| where('? == (select count(fact_id) from votes where votes.fact_id == facts.id)', count)}
end
Fact.by_user(1).vote_count(0)
vote_count范围有点像sqly,但你可以链接这些查找器,但你也可以看到底层的sql:
Fact.by_user(1).vote_count(0).to_sql
除了你的评论之外,你可以通过首先宣布关系来在纯粹的Arel中做同样的事情:
f = Arel::Table.new(:facts)
v = Arel::Table.new(:votes)
u = Arel::Table.new(:users)
然后编写查询并将其呈现给sql。
sql = f.join(u).on(f[:user_id].eq(1)).where('0 == (select count(fact_id) from votes where votes.fact_id == facts.id)').to_sql
您可以使用运算符对列进行操作: f[:user_id].eq(1)
然后使用它:
Fact.find_by_sql(sql)
我确信您可以采取更多优雅的语法(没有'where 0 == ...')。另外我很确定Rails3范围在幕后使用Arel - http://m.onkey.org/active-record-query-interface
答案 1 :(得分:1)
我最终用以下范围解决了这个问题:
scope :not_voted_on_by_user, lambda {|user_id| select("distinct `facts`.*").joins("LEFT JOIN `votes` ON `facts`.id = `votes`.fact_id").where(["votes.user_id != ? OR votes.user_id IS NULL",user_id])}