views:

93

answers:

1

Here's the scoop:

As a learning exercise, I'm trying to write a Rails clone of one of the many location-based games out there (Foursquare, Gowalla, etc.) I have Users who create and check in to Stores.

In ActiveRecord terms:

:user has_many :stores
:store belongs_to :user

But now I've created a third model - Checkins. The table behind the model contains two fields, user_id (to record which User made the checkin), and store_id (to record what Store that User checked in to).

Once again, in AR terms:

:checkin belongs_to :user
:checkin belongs_to :store

:user has_many :checkins
:store has_many :checkins

This all works well and good - in my User and Store views, I can call @user.checkins and @store.checkins respectively. The only thing is, in this manner I can only retrieve the user_id or store_id, where I really want to get the username or store name. So I figure the intermediate checkin table lends itself perfectly to a usage of :through:

:user has_many :stores, :through => :checkins
:store has_many :users, :through => :checkins

It makes sense, but the thing is that a User already has_many Stores - the ones he's created! And on his user page, I need to list both the Stores he's created AND the ones he's checked in to. I'm still trying to wrap my head around has_many_and_belongs_to so I'm not sure if that would set me in the right direction. Anyone care to offer a clue?

A: 

Rails makes it easy to handle this situation. One solution: your user can use a different relationship name for the second set of stores. For example:

class Checkin
  belongs_to :store
  belongs_to :user
end

class Store
  belongs_to :user
  has_many :checkins
end

class User
  has_many :stores
  has_many :checkins

  has_many :visited_stores, :through => :checkins, :source => :store
end

Using the :source option tells ActiveRecord to look for the Checkin association :store when building the list of visited stores. Alternatively, you could've said

has_many :created_stores, :class_name => "Store"
has_many :stores, :through => :checkins

In this case, you're renaming the owned stores instead of the visited ones.

chrisdinn
Perfect! I had seen the :source attribute but wasn't completely sure how to use it. Thanks!
Tim