0

I have a habtm relationship implemented with a model that represents the join (because the join has attributes):

class Person
  has_many :person_photos
end

class PersonPhoto
  # has a person and a photo id, and a couple of 
  # other attributes that aren't relevant
end

class Photo
  has_many :person_photos
end

I'd like to add a method to the Photo class to get a list of people that are not in that photo. For the life of me I can't figure it out. Is it easy to do?

Stewart Johnson
  • 14,281
  • 7
  • 61
  • 70

2 Answers2

1

Try that maybe, in your photo model...

def people_not_tagged
    People.where("id NOT IN (?)", people_ids.empty? ? "" : people_ids)
end
Stewart Johnson
  • 14,281
  • 7
  • 61
  • 70
Robin
  • 21,667
  • 10
  • 62
  • 85
  • I like the simplicity of this one, but the SQL it generates is: SELECT `people`.* FROM `people` WHERE (id NOT IN 1,2) and that barfs. – Stewart Johnson Jan 04 '12 at 03:28
  • Ahh -- include brackets around the ? and it works! (I edited the answer to fix it.) Thanks! – Stewart Johnson Jan 04 '12 at 03:32
  • What are you building? If it's not a very small, personal app, you'll get a huuuge number of People! You might want to be more specific. – Robin Jan 04 '12 at 03:36
  • It's an in-house app so there won't be thousands of people. Actually the models aren't even People and Photo, I just used those names to make the example easier to understand. – Stewart Johnson Jan 04 '12 at 03:46
  • Ok :) But with this method at least, it's easy to paginate if you need to. – Robin Jan 04 '12 at 03:48
  • Ah... it breaks if there are no people already tagged in the photo, it ends up with `(id NOT in (NULL))` :-/ – Stewart Johnson Jan 04 '12 at 04:44
  • Updated after testing -- the || version didn't work (still returned no people when there were none already tagged). – Stewart Johnson Jan 04 '12 at 07:33
  • Since the sql generated was `in (NULL)`, for some reason, I thought that people_ids was null... but it's an empty array, obviously ^^. But anyways, you got it now ^^. – Robin Jan 04 '12 at 14:22
0

You could try having person has_many photos through person_photos and photo has_many people through person_photos.

Rails docs for has_many through

Then photo.find(1).people would list all the people in photo 1

Then using array subtraction people_not_in_photo = People.all - photo.find(1).people would, I think, give you what you're looking for.

Stackoverflow question on subtracting arrays

Community
  • 1
  • 1
Edward
  • 3,429
  • 2
  • 27
  • 43
  • `people_not_in_photo = People.all - photo.find(1).people`. As is, it would really heavy, right? Maybe `people_not_in_photo = People.select(:id).map(&:id) - photo.find(1).people_ids` would be a bit better. But still, if there is a lot of users, I don't think it's a viable solution. – Robin Jan 03 '12 at 17:35