2

I am noticing a relation problem that I may have created.

I started off with a Photo model. An admin could upload photos and they would exist on the site.

In a later iteration Albums were added into the codebase so that a collection of photos could be organized on its own page.

Album
  has_many :photos, inverse_of: :album
Photo
  belongs_to :album, inverse_of: :photo

After playing with the above I noticed that a Photo can ever only belong to one Album. That has been ok.

Now a new issue arises. I'd like to add photos of members of the staff which are also their own model.

I also have some special logic in my Photo model to handle using a specific upload service (filepicker).

Staff
  field :name, type: String

How can I make it so Staff can have their own photos? Should I create a new model StaffPhoto for denormalization? I was thinking of having Photo either embedded or belong_to Staff but then I'm not sure if it makes sense to belong to both an Album and a Staff member. The only thing making the most sense to me right now is creating a separate model and abstracting the upload service logic into a module and including it into both. However I could be wrong. The important part is that Photo's overall will exist on their own, or a part of an album, or a part Staff member (more than one photo).

Any suggestions on how to model this?

Daniel Fischer
  • 3,042
  • 1
  • 26
  • 49

2 Answers2

1

What you are looking for is perfectly described in the guides: http://guides.rubyonrails.org/association_basics.html#polymorphic-associations

You could create a polymorphic association:

class Photo < ActiveRecord::Base
  belongs_to :photoable, :polymorphic => true
end

class Album < ActiveRecord::Base
  has_many :photos, :as => :photoable
end

class Staff < ActiveRecord::Base
  has_many :photos, :as => :photoable
end
Zippie
  • 6,018
  • 6
  • 31
  • 46
  • If I do that to an existing model and existing entries, how does that affect older records? Do I need to run any code to migrate field data or attributes? I assume it saves in a different way... – Daniel Fischer Apr 09 '13 at 21:32
  • yes it does affect then in a different way, check out the migration file in the docs behind the 'imagable' or in your case 'photoable' interface, it doesn't contain a additional column to distinguish the polymorphic association. you are still in the development stage, right? if not create a seperate photo table for the other table or modify it theough the console – Zippie Apr 09 '13 at 21:39
  • I'm trying to find this migration file in the docs. Can you send me a link please? It's already in production, so if I modify the model I will have to modify the records through the console. But I'm at a loss of how to do that... – Daniel Fischer Apr 09 '13 at 22:14
  • Also this is Mongoid not ActiveRecord... just clarifying because you linked to RubyonRails guides. – Daniel Fischer Apr 09 '13 at 22:16
  • checkout the second answer here: http://stackoverflow.com/questions/3826600/mongoid-relational-polymorphic-association – Zippie Apr 10 '13 at 10:01
1

A polymorphic association is good when you have things which belong to different owner classes; e.g. when you have photos which could be from either a movie or a tv-show, and you have movies and tv-shows already modeled in your database -- then you'd use a polymorphic association to refer to the "owner" object of a photo.

Typically you would not want to model Admins, Staff, and Users with separate models. A cleaner way to do this is to model all of them as Users, and then have roles and permissions modeled separately, so e.g. everybody could potentially be an Admin.

If you chose this sort of modeling of users, then all you need in your photo model is a user_id to model who the owner is -- and you don't care if that's an admin or staff, or a regular user.

If you also want to model how the photos are used, e.g. the admin photos are completely different from the staff photos (e.g. admin photos are backgrounds, staff photos are head-shots), then you might want to also assign a "photo type" attribute to the photos.

I don't think that in your scenario a polymorphic association is the best solution.

Please check out the Railscast on Roles/Authorization, so you can model the Admin/Staff in just one model.

http://railscasts.com/episodes?search=authorization


Regarding Embedded Documents:

there are few considerations for using embedded documents:

  • does the embedded document augment/enrich the parent document?
  • not to exceed the 16MB MongoDB record size
  • if you ever need to search across all embedded documents

In case of photos, you would want to embed references to your photos, not the photos themselves, because of the large size a photo can have.

In case of your application, how many photos are there for a user? Can their number grow to a considerable amount over time? If yes, then you probably don't want to embed them.

Does the photo augment the user record? e.g. is it an avatar photo? if not, then you probably don't want to embed it.

Do you ever need to search across the photos? Probably not. Other kinds of embedded document might need to be searched from the top level, and then you can not embed them.

Tilo
  • 33,354
  • 5
  • 79
  • 106
  • Then would a embedded document make more sense over a polymorphic association? Embedded seems to make more sense in that shared way you're speaking of. – Daniel Fischer Apr 15 '13 at 04:35
  • Probably not, but see the amendment to my answer above – Tilo Apr 15 '13 at 17:39
  • Thank you. The photo document currently isn't very large. The photo itself is stored on s3 so the photo document just has a file path attribute to the photo itself so I don't think the size can grow too large. I initially thought that photos would have to exist on their own but now it seems it's more of a functionality that other models will have which has confused me on whether to make it embedded or polymorphic. – Daniel Fischer Apr 16 '13 at 00:14