views:

126

answers:

1

I'm working on an application that allows users to associate images with specific events. Events are owned by a user. The easy solution would of course be:

class Image < ActiveRecord::Base
  belongs_to :event
end

class Event < ActiveRecord::Base
  has_many :images
  belongs_to :user
end

class User < ActiveRecord::Base
  has_many :events
  has_many :images, :through => :events
end

Except! There is one problem. I also want my users to be able to own images directly, without an intermediary event. If I use polymorphic association "conventionally" here, then obviously user.images won't work properly. Should I just hold my nose, use an :as => :event_images to disambiguate, and define user.all_images if that need ever comes up? Should I have all images owned directly by users and optionally associated with events somehow? (With, of course, a validation to ensure consistency... but that seems code-smelly.) Is there a third solution that is prettier than either of these?

A: 

I often find it useful to forget the ActiveRecord DSL and work with the data model directly when defining complex relationships. Once the data model is correct you can then map it into model statements.

It is not quite clear from your question if Images can be owned by a User or an Event, of if they can be owned by both at the same time. That issue will determine the data model you use.

If an Image can be owned by both, the Image table will need a reference to both a user_id and an event_id, which may need to be nullable depending on your use-case (user or event being optional relationships). If the Image can only be owned by one, you could set up some sort of polymorphic ownerable relationship that maps owners to the right owner table (owner_id, owner_type etc etc).

Assuming it can belong to both:

class Image < ActiveRecord::Base
  belongs_to :event
  belongs_to :user
end

class Event < ActiveRecord::Base
  has_many :images
  belongs_to :user
end

class User < ActiveRecord::Base
  has_many :events
  has_many :images
  has_many :event_images, :through => :events, :class_name => "Image"
end
Toby Hede