What's the best way to model this?

Let's say I have a user model and a contacts model (contacts contains
name, phone number, email, etc. of people that the user knows). The
models would be


has_many :contacts


belongs_to :user

Now let's say I wanted to introduce groups, where the user could place
certain contacts into groups. Some contacts would be in multiple
groups, others wouldn't be in groups at all. What would be the best
way to model this?

I was thinking


has_many :contacts
has_many :groups


belongs_to :user
has_and_belongs_to_many :contacts


belongs_to :user
has_and_belongs_to_many :groups

But I'm not sure if this really works. How can I guarantee that a
contact in a group really belongs to the user (maybe I can't through
the model and need to do it in code but that seems so unRails like).


Any ideas?

Hi there,

The way I would do it would be like,


has_and_belongs_to_many :users


belongs_to :group
has_and_belongs_to_many :contacts,
           :class_name => 'User',
           :join_table => 'user_contacts',
           :association_foreign_key => :contact_id,
           :foreign_key => :user_id,
           :after_add => :make_contact_to_contact,
           :after_remove => :remove_my_contact


  # I am there contact so they are my contact
  def make_contact_to_contact(contact)
    contact.contacts << self unless contact.contacts.include?(self)

  # Ok lets no be friends any more :frowning:
  def remove_my_contact(contact)
    contact.contacts.delete(self) rescue nil

In the above I take it that a contact is just another User, hence the
user_contact table.

With the above the Group is at the top so you could have something like

user = User.find(:first)

user.groups.first.users --> gives all the users from that users first
group, if you get what I mean.



Thanks for the response but actually contacts are not other users - I
should have made that clearer. Rather than it being a social-graph
type application, it's more like contact management, so contacts
belong to the user but are not associated with other users in any way.
If they were, your implementation makes perfect sense, but we're
actually dealing with 3 models here not 2.