2010-11-08 8 views
3

J'ai un modèle Fact, qui has_many:votes. Les votes ont aussi un champ user_id. Je voudrais exprimer ce qui suit dans un champ pour le modèle Fact: Donnez-moi tous les faits qui ont 0 votes avec un user_id égal à X.Arel Aggregations, Count, Jointure externe?

Je ne suis pas tout à fait assez familier avec Arel pour comprendre comment je pourrais s'attaquer à cela. Des idées?

+0

ce qui est Arel? Peux-tu poster un lien? – s84

+0

@Sam: http://stackoverflow.com/questions/2770415/what-exactly-is-arel-in-rails-3-0 – Zabba

Répondre

1

Je fini par résoudre ce problème avec la portée suivante:

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

Cela fonctionne:

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) 

Le champ d'vote_count est un peu sqly mais vous pouvez enchaîner ces viseurs comme bon vous semble, vous pouvez également voir le sql sous-jacente avec:

Fact.by_user(1).vote_count(0).to_sql 

Et plus à votre commentaire, vous pourriez faire la même chose en pure Arel en déclarant d'abord les Relations:

f = Arel::Table.new(:facts) 
v = Arel::Table.new(:votes) 
u = Arel::Table.new(:users) 

Ensuite, composer la requête et la rendre en 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 

Vous pouvez agir sur des colonnes avec des opérateurs:f[:user_id].eq(1)

ensuite l'utiliser:

Fact.find_by_sql(sql) 

Je suis sûr que theres beaucoup plus que vous pouvez faire pour obtenir un plus élégant syntaxe (sans le 'où 0 == ...'). Aussi je suis assez sûr portées Rails3 utilisent Arel dans les coulisses - http://m.onkey.org/active-record-query-interface

+0

Oui, c'est similaire à ce que je fais maintenant; Ma question est comment faire cela en utilisant Arel, ou au moins une relation active. En outre, en guise d'ergot, le champ user_id décrit dans ce scénario appartient au modèle Vote. –

Questions connexes