Mike T
Mike T

Reputation: 4787

HABTM relation find all records, excluding some based on association

I've looked at some of the similar SO posts relating to this but I'm struggling to get my head around it.

I have a habtm relation between Projects and Users. I'm trying to find all the Projects that a particular user does not belong to but I don't know how.

I've tried this sort of thing:

Project.where('project_id != ?', user.id)

But it's also obviously wrong.

I'm using rails 3.2.x

Many of the answers relating to this mention scopes but I haven't come across them before (I'm still very new to Rails).

I just found this post with one answer suggesting: Project.where('id not in (?)', user.projects)

which seems to work, except when user.projects is empty. I'm trying Project.where('id not in (?)', (d.projects.empty? ? '', d.projects)) as is suggested in JosephCastro's answer comment thread but it's giving me a syntax error on the second d.projects.

Edit

Project model snippet that relates to Users

class Project < ActiveRecord::Base
  attr_accessible ...
  has_and_belongs_to_many :users, :before_add => :validates_unique

and then

class User < ActiveRecord::Base
  attr_accessible ...
  has_and_belongs_to_many :projects

Upvotes: 2

Views: 1855

Answers (2)

saundersj
saundersj

Reputation: 11

From Matt's reply above, which was extremely helpful.

I had trouble with this for a while. I attempted to use the following:

scope :not_belonging_to, lambda {|developer| where('id NOT IN (?)', developer.projects.empty? ? '' : developer.projects) }

But I received the following error:

SQLite3::SQLException: only a single result allowed for a SELECT that is part of an expression:

I found I needed to update the scope, adding .ids on the end. See below:

scope :not_belonging_to, lambda {|developer| where('id NOT IN (?)', developer.projects.empty? ? '' : developer.projects.ids) }

Upvotes: 1

Matt
Matt

Reputation: 14038

You can place a scope in your Project model like so:

scope :not_belonging_to, lambda {|user| joins(:projects_users).where('projects_users.user_id <> ?', user.id) }}

This assumes your join table name matches rails convention for HABTM associations

To then get projects that a user doesn't belong to, first find your user, then pass them to the scope like so:

@user = User.find(params[:id]) # example
@unowned_projects = Project.not_belonging_to(@user)

On reflection, that scope won't work as it will find projects that have more than one developer, if one of those is your guy.

Instead, use the following:

scope :not_belonging_to, lambda {|user| where('id NOT IN (?)', user.projects.empty? ? '' : user.projects) }

Upvotes: 3

Related Questions