I have a Fact
model, which has_many
:votes
. Votes also have a user_id
field. I'd like to express the following in a scope for the Fact
model: Give me all Facts which have 0 votes with a user_id
equal to X.
I'm not quite familiar enough with Arel to understand how I might tackle this. Ideas?
This works:
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)
The vote_count scope is a bit sqly but you can chain these finders however you like, you can also see the underlying sql with:
Fact.by_user(1).vote_count(0).to_sql
And further to your comment, you might do the same in pure Arel by first declaring the Relations:
f = Arel::Table.new(:facts)
v = Arel::Table.new(:votes)
u = Arel::Table.new(:users)
Then composing the query and rendering it to 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
You can act on columns with operators: f[:user_id].eq(1)
Then using it:
Fact.find_by_sql(sql)
I'm sure theres a lot more that you could do to get a more elegant syntax (without the 'where 0 == ...' ). Also I'm pretty sure Rails3 scopes use Arel behind the scenes - http://m.onkey.org/active-record-query-interface
我最终用以下范围解决了这个问题:
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])}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.