A Model Belongs to Many Model

Hi,

I have a design question. I have 4 models, Photo, Trip, Destination, and
Hotel. I want Trip, Destination, and Hotel to have Photos. A Photo
always belongs to a Destination but at the same time it can belongs to
Trip and Hotel. Most of the time a Photo belongs to Trip & Destination.
The way I have it right now is the following:

class Trip < ActiveRecord::Base
  :has_many :photos

class Destination < ActiveRecord::Base
  :has_many :photos

class Hotel < ActiveRecord::Base
  :has_many :photos

class Photos < ActiveRecord::Base
  :belongs_to :trip
  :belongs_to :destination
  :belongs_to :hotel

photos table will have trip_id, destination_id, and hotel_id. And since
a record in photo table doesn’t always belongs to trip or hotel, trip_id
and hotel_id can be null. That’s should be ok right to have null in the
foreign key? Is this the best way to do it or there’s a better design to
this problem? Moreover, I want to be able to easily add another model
that I can attach photos to it.

Thanks!

On 6 May 2008, at 23:57, Fajar A b wrote:

photos table will have trip_id, destination_id, and hotel_id. And
since
a record in photo table doesn’t always belongs to trip or hotel,
trip_id
and hotel_id can be null. That’s should be ok right to have null in
the
foreign key?
Unless you’ve explicitly asked for it not to be null

Is this the best way to do it or there’s a better design to
this problem? Moreover, I want to be able to easily add another model
that I can attach photos to it.

You may be interested in a polymorphic association:
make photos have columns subject_id, and subject_type.
then
class Photo < ActiveRecord::Base
belongs_to :subject, :polymorphic => true
end

class Trip < AR::Base
has_many :photos, :as => :subject
end

class Destination < AR::Base
has_many :photos, :as => :subject
end

etc…

photo.subject will return an instance of the appropriate class.

Fred

Frederick C. wrote:

On 6 May 2008, at 23:57, Fajar A b wrote:

photos table will have trip_id, destination_id, and hotel_id. And
since
a record in photo table doesn’t always belongs to trip or hotel,
trip_id
and hotel_id can be null. That’s should be ok right to have null in
the
foreign key?
Unless you’ve explicitly asked for it not to be null

Is this the best way to do it or there’s a better design to
this problem? Moreover, I want to be able to easily add another model
that I can attach photos to it.

You may be interested in a polymorphic association:
make photos have columns subject_id, and subject_type.
then
class Photo < ActiveRecord::Base
belongs_to :subject, :polymorphic => true
end

class Trip < AR::Base
has_many :photos, :as => :subject
end

class Destination < AR::Base
has_many :photos, :as => :subject
end

etc…

photo.subject will return an instance of the appropriate class.

Fred

Thanks for the reply Fred. I’d like to be able to do destination.photos
which will returns all photos that belongs to destination. Can I do this
with polymorphic? What I understand is when I use your setup and do
destination.photos it will only return photos that has subject_type =
“Destination”. SOme photos belong to a trip and also a destination.

Thanks!

On 7 May 2008, at 03:14, Fajar A b wrote:

Thanks for the reply Fred. I’d like to be able to do
destination.photos
which will returns all photos that belongs to destination. Can I do
this
with polymorphic? What I understand is when I use your setup and do
destination.photos it will only return photos that has subject_type =
“Destination”. SOme photos belong to a trip and also a destination.

Oops, I’d glossed over the fact that some photos belong to more than
one of destination/trip/etc…
Perhaps a has_many :through, where the association to destination/trip/
etc on the join table is polymorphic ?

Fred

Frederick C. wrote:

On 7 May 2008, at 03:14, Fajar A b wrote:

Thanks for the reply Fred. I’d like to be able to do
destination.photos
which will returns all photos that belongs to destination. Can I do
this
with polymorphic? What I understand is when I use your setup and do
destination.photos it will only return photos that has subject_type =
“Destination”. SOme photos belong to a trip and also a destination.

Oops, I’d glossed over the fact that some photos belong to more than
one of destination/trip/etc…
Perhaps a has_many :through, where the association to destination/trip/
etc on the join table is polymorphic ?

Fred

This is what I ended up doing:

class Photo < ActiveRecord::Base
belongs_to :user
belongs_to :destination
belongs_to :content, :polymorphic => true

class Destination < ActiveRecord::Base
has_many :photos

class Trip < ActiveRecord::Base
belongs_to :user
belongs_to :destination

This way I can do destination.photos and get all photos for that
destination even though the content is Trip or anything else. What do
you guys think?

Andrew,
Destination usually a city and hotel must belongs to a destination.

Fajar A b wrote:

Thanks for the reply Fred. I’d like to be able to do destination.photos
which will returns all photos that belongs to destination. Can I do this
with polymorphic? What I understand is when I use your setup and do
destination.photos it will only return photos that has subject_type =
“Destination”. SOme photos belong to a trip and also a destination.

Thanks!

Polymorphics are certainly the way to go here. Once you understand them
you will use them everywhere :slight_smile:

If you declare the associations as Fred described you will be able to
call destination.photos, which will return an array of photo objects.

You are also correct about one photo belonging to one model. However,
are you sure that photos really need to belong to destinations, trips,
and hotels or would it be better attaching photos to one, then using the
associations to pull them back again?

(as an aside, I am a little confused about the difference between a
destination and a hotel. Surely a hotel is one kind of destination?)

Fajar A b wrote:

This is what I ended up doing:

class Photo < ActiveRecord::Base
belongs_to :user
belongs_to :destination
belongs_to :content, :polymorphic => true

class Destination < ActiveRecord::Base
has_many :photos

class Trip < ActiveRecord::Base
belongs_to :user
belongs_to :destination

This way I can do destination.photos and get all photos for that
destination even though the content is Trip or anything else. What do
you guys think?

Andrew,
Destination usually a city and hotel must belongs to a destination.

I must be missing something here - where is “has_many :photos, :as =>
:content” used?

Looks like your on the right track, but let me have a crack (without
fully understanding your requirements).

We have a few moving parts - users, photos, destinations, and trips. A
user wants to plan their holiday by building up a series of destinations
into a trip. They may want to look at photos of their destinations to
choose good looking hotels to stay at. Users can also upload photos of
destinations they have visited for others to look at. Given this, the
models would look something like:

class User < ActiveRecord::Base
has_many :trips
has_many :photos
has_many :destinations, :through => :trips
end

class Trip < ActiveRecord::Base
belongs_to :user
has_many :destinations
has_many :photos, :through => :destinations # Is this useful?
end

class Destination::ActiveRecord::Base
belongs_to :trip
has_many :photos, :as => photographable
has_many :users, :through => trips # So we can look up users who have
been here.
end

class Photo < ActiveRecord::Base
belongs_to :user
belongs_to :destination
has_many :trips, :through => :destinations # Not sure if this works
belongs_to :photographable, :polymorphic => true
end

Now you can call the following in your controllers/views:

user.trips # List all the trips a user has created
user.photos # List all the photos a user has uploaded
trip.destinations # List the destinations associated with a trip
destination.photos # List all the photos for a given destination
trip.photos # Grab all the photos attached to all the
destinations in this trip

etc.