views:

212

answers:

1

I'm trying to create a named scope like User.not_in_project(project) but I can't find the right way.

I have Users, Projects and Duties as a join model:

class User < ActiveRecord::Base
  has_many :duties, :extend => FindByAssociatedExtension
  has_many :projects, :through => :duties
end

class Duty < ActiveRecord::Base
  belongs_to :user
  belongs_to :project
end

class Project < ActiveRecord::Base
  has_many :duties
  has_many :users, :through => :duties
end

I tried with a named_scope similar to this find clause:

User.all(:joins => :duties, :conditions => ['duties.project_id != ?', my_project])

But that doesn't return me users who don't have my_project but users that have a project other than my_project.

In other words, I want the named scope to behave exactly like this method:

def self.not_present_in p
  self.all.reject{|u| u.projects.include?(p)}
end

How can I do that?

+1  A: 

Thinking in SQL, the query should be something like:

select id
  from users
 where id not in (select id
                    from users join duties on users.id = duties.user_id
                    join projects on duties.project_id = projects.id
                   where projects.id = %)

But I'm not too sure how it would work using named_scope. I'd say use something like

def self.not_present_in p
  find_by_sql ["select id from users where id not in (select id from users join duties on users.id = duties.user_id join projects on duties.project_id = projects.id where projects.id = ?)", p]
end

Not as pretty as using AR, but will work (and save you some queries, probably).

Yaraher
Thanks Yaraher, the sql query you provide works as I want with a minor fix. I had to substitute "id" with "users.id" after the second select for not to be ambiguous.However, I cannot use a find_by_sql in a named_scope :(.
Manuel M
But why do you need it to be a named scope? For merging it with another methods?Unless that's the case, it should work fine. And if you do want to refine it a bit later, you could always submit an options hash akin of how AR uses, and concatenating/merging it with the find_by_sql query. Could be a bit of extra work but it will be probably as close as you can get. ORMs not always keep us from using SQL :)
Yaraher