Question

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?

Was it helpful?

Solution 2

I ended up solving this problem with the following scope:

  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])}

OTHER TIPS

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top