views:

109

answers:

3

Sorry for the vague title, but this is kind of hard to put into one line.

I have a database full of contact information, and I want to be able to put those different contacts into groups which will also be stored in the database.

So, maybe I have 2 groups, "coworkers" and "neighbors", I want to be able to see a list of all my contacts and be able to add individual contacts to one or more groups.

I'm kind of confused as where to begin with this, could I get some basic outlines of how this might best be implemented? Thanks.

A: 

You could structure a Ruby on Rails database to be :

Contact ( first_name:string, last_name:string, title:enum number:string, cell:string, notes:text, email:string ) => many_many :groups (or has_many :groups, :through=> :contact_group)
Contact_Group { group_id:integer, contact_id:integer }
Group   ( name:string ) => many_many :contacts ) (or has_many :contacts, :through=> :contact_group)

That might be the general idea. You also could do relational fields.

CodeJoust
+2  A: 

Well, you've got two models, Contact and Group. These two guys are clearly going to have their own tables (probably 'contacts' and 'groups' if you're following the Rails conventions). Since a contact can be in many groups, and a group can have many contacts, you've got what's called a many-to-many relationship between these models. There are basically two ways to implement this in Rails: has_and_belongs_to_many or has_many :through. Which one is best for you will depend a little on your situation.

has_and_belongs_to_many is probably the path of least resistance. You put a couple lines in your models like so:

# contact.rb
has_and_belongs_to_many :groups

# group.rb
has_and_belongs_to_many :contacts

...and create a table called 'contacts_groups' with the columns contact_id and group_id, and you're basically good to go. Easy peasy.

On the other hand, there are some advantages to using an association model with has_many :through. In this approach, you create another model, say, GroupMembership, and set up your models like so:

# contact.rb
has_many :group_memberships   # this isn't strictly required, but I'd recommend it
has_many :groups, :through => :group_memberships

# group_membership.rb
has_many :groups
has_many :contacts

# group.rb
has_many :group_memberships   # again, recommended but not required
has_many :contacts, :through => :group_memberships

This gives you most of the same convenience methods as has_and_belongs_to_many, and also lets you store any extra data you might want about the association, like the date they joined the group or the reason they were added. Even if you don't have any of that now, it's nice to account for the possibility of adding it later. Also, this lets you take a more RESTful approach to adding and removing contacts to and from groups, if that's something you're interested in, since you can model it in terms of creating and destroying GroupMembership resources.

By and large, I tend to lean toward the latter approach, especially as I've gotten more in to RESTful architectures. On the other hand, if you're not worried about REST and you're certain you'll never want to keep any extra information about memberships, has_and_belongs_to_many is probably simpler and requires less code to get working. For more in-depth information on the differences and implementation details, see the ActiveRecord Associations API docs.

John Hyland
A: 

You don't want to use the has_and_belongs_to_many approach. It's deprecated. Please read the API and make sure you implement a join model / has_many :through approach. The API will tell you how to do this and also mention why has_and_belongs_to_many is bad.

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

DFischer
The only deprecation I see on has_and_belongs_to_many is for defining fields on the join table to be added as attributes to objects pulled through the association (which would indeed suggest that you want a real join model instead). Indeed, the API you link to states that "[c]hoosing which way to build a many-to-many relationship is not always simple. If you need to work with the relationship model as its own entity, use has_many :through. Use has_and_belongs_to_many when... you never work directly with the relationship itself."That said, I do lean toward join models in most cases.
John Hyland