Galaxy
Galaxy

Reputation: 3400

Rails associations - ideas for best practice

A question regarding Rails associations.
Consider the following models:

People and events can have many images.
Images uploaded to an event, need to have the ability to be associated with multiple people.

This means that there are two relationships between people and images.
One where images are uploaded directly on the person. And one where a person is tagged in an event.

Can there also be a relationship between a person and an event based on the fact they were tagged in one (or multiple) images in an event? In this regard, it's a sort of image tagging system where associations are created based on what event people are tagged in.

Wondering what is the best practice in Rails to create this association? Any help or advice is greatly appreciated!

Upvotes: 5

Views: 842

Answers (3)

nathanvda
nathanvda

Reputation: 50057

In rails it is definitely possible to define a join-table that has extra fields. So in this case I would define the following table:

class LinkedImage
  belongs_to :person
  belongs_to :image

  OWNER=1
  TAGGED=2

  validates :relation_type, :inclusion => {:in => [OWNER, TAGGED]}
end

This table would link an image to a person, and has an extra field relation_type (you could think of a more appropriate name maybe), which now can have two values: 1 (for the OWNER, meaning the image was directly uploaded to the person), and 2 (the person is tagged in the image). Aside from the relation, maybe you want to store something extra, like the position in the image, an extra comment, then you could easily add that here as well.

And the person would look like:

class Person
  has_many :linked_images
  has_many :uploaded_images, :class_name => Image, 
                             :through => :linked_images, 
                             :conditions => "relation_type=#{LinkedImage::OWNER}"
  has_many :tagged_in_images, :class_name => Image,
                              :through => :linked_images,
                              :conditions => 'relation_type=#{LinkedImage::TAGGED}"
end 

and the code for Image could be similar.

I hope this helps.

Upvotes: 2

sarvavijJana
sarvavijJana

Reputation: 1212

I am not absolutely sure about best practice, but there is a chance to solve your case in simple way, as far as i understand you:

We have:

Event ... has_many :photos; Photo ... belongs_to :event

and solution is to create some intermediary ActiveRecord class

People ... has_many :photos, :through photo_mappings

PhotoMapping ... belongs_to :user; belongs_to :photo

Have a nice AR associations best practice1

Upvotes: 2

cicloon
cicloon

Reputation: 1099

I don't know if this is the best approach, but I would do something like this:

class User < ActiveRecord::Base
  has_many :images, :as => :owner
  has_many :tags
  has_many :tagged_images, :through => :tags, :source => :image

  has_many :tagged_events, :finder_sql => %q( SELECT `events`.* FROM `events`, `images` WHERE `events`.id = `images`.owner_id AND `images.owner_type ="Event" `
                                    WHERE (`images`.id IN (#{tagged_image_ids.join(',')}) ))


end

class Event < ActiveRecord::Base
  has_many :images, :as => :owner

  has_many :tagged_users, :finder_sql => %q( SELECT `users`.* FROM `users`, `images` WHERE `users`.id = `images`.owner_id AND `images.owner_type ="User" `
                                    WHERE (`images`.id IN (#{image_ids.join(',')}) ))


end

class Tag < ActiveRecord::Base
  belongs_to :user
  belongs_to :image  
end

class Image < ActiveRecord::Base
  belongs_to :owner, :polymorphic => true
  has_many :tags
  has_many :tagged_users, :through => :tags, :source => :user
end

Note: Using finder_sql is not the best in Rails, because for example it doesn't allow you to add new tagged images just using the relationship, but it works fine for reading.

Upvotes: -1

Related Questions