Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

rails complex many-to-many query

I've got 3 models: User, Team, and Membership -

class Team < ActiveRecord::Base
  has_many :memberships
  has_many :members, :through => :memberships, :source => :user
end

class User < ActiveRecord::Base
  has_many :memberships, :dependent => :destroy
  has_many :teams, :through => :memberships

  def team_mates
    teams = Team.where(:members => id)
    team_mates = teams.members
  end
end

class Membership < ActiveRecord::Base
  belongs_to :user
  belongs_to :team

  validates :user_id, :presence => true
  validates :team_id, :presence => true
end

And, I can't quite figure out how to write the team_mates method in the User model. It should return an array of the other users that are in a team with the current_user. My thought is that I should be useing a scope to limit Team to only include teams where the current user is a member but I can't quite figure out the syntax. Any help on this would be greatly appreciated.

Thanks!

like image 353
spinlock Avatar asked Apr 08 '11 05:04

spinlock


2 Answers

Use the membership table to find users who share any team with the user you are calling the method on. Then to filter out duplicate users who share more than 1 team with current user, use distinct.

I haven't tested the below code, but hopefully it will get you on the right path:

def team_mates
  m = Membership.scoped.table
  Users.join(m).where(m[:team_id].in(team_ids)).project('distinct users.*')
end

UPDATE

Looks like some of the Arel methods in that answer don't have an easy mapping back to ActiveRecord land. (If someone knows how, I'd love to know!) And also it returns the 'current user'. Try this instead:

def team_mates
  User.joins(:memberships).where('memberships.team_id' => team_ids).where(['users.id != ?', self.id]).select('distinct users.*')
end
like image 171
ctcherry Avatar answered Oct 29 '22 01:10

ctcherry


How about?

User.joins(:memberships).joins(:teams).where("teams.id" => id).uniq
like image 41
digitalWestie Avatar answered Oct 29 '22 01:10

digitalWestie