Polymorphic class associations

Hi there,

I'd be happy if someone can help me with the following:
The application is for uploading all kinds of datafiles which should be
displayed accordingly to their mimetypes.

This is the class/database hierarchy of what I want to archive:

Class:Filegroup
  has_many :binary
  Attributes are e.g. groupname, timestamps of upload/update and so on

Class:Binary
  This is the generall description of the uploaded file
  Attributes included are e.g. original_filename, mimetype and so on

If someone is uploading a file with a known mimetype, a (sub-)class
should be created with specific details about the file e.g.

Class:Image
  Including width, height...

Class:Text
  Textstyle (php, xml)...

I'd like to access the list of *all* files through something like:
Filegroup.find(xxx).files iterates over it and render it automatically
as it is specified in each of those sub-classes (so images whould be a
thumbnail, text is shown fully and binary just a simple download link)

I found the Polymorphic-attribute for the database associations but this
is the other way round, isn't it?
Also I took a look at
http://archive.robwilkerson.org/2009/08/26/learning-ruby-on-rails-file-upload/index.html
but this isn't exactly what I need because the class which should be
used should be defined automatically.
(E.g. somewhere is specified which class should be used for which
mimetype)

Thank you for your time and help.

I believe you need a mix of:

  • STI from Binary to Image, Text etc.

  • has_many relationships from Filegroup to

these different classes.

I set-up a project on

https://github.com/petervandenabeele/files

with as core files:

class Binary < ActiveRecord::Base

end

class Filegroup < ActiveRecord::Base

has_many :binaries

has_many :images

has_many :texts

end

class Image < Binary

def show

“this is an image of width #{width} and height #{height}”

end

end

class Text < Binary

def show

“This is a text of size #{size}”

end

end

and schema.rb :

ActiveRecord::Schema.define(:version => 20111203233119) do

create_table “binaries”, :force => true do |t|

t.string “filename”

t.integer “filegroup_id”

t.string “type”

t.datetime “created_at”

t.datetime “updated_at”

t.integer “height”

t.integer “width”

t.integer “size”

end

create_table “filegroups”, :force => true do |t|

t.string “groupname”

t.datetime “created_at”

t.datetime “updated_at”

end

end

And then I can call:

fg.images.build

fg.texts.build

to build instances of derived classes, but also

fg.binaries

to get back all binaries (of different subclasses) where each

binary (image, text) has it’s own class specific implementation

of a show method (different for an Image and for a Text).

Is this what you where looking for ?

Peter

Dear Peter Vandenabeele,

thanks for your really long answer and sorry for my late reply.. I'm
really short on time these days.. :frowning:

A day before you wrote your answer I came up with a different solution:

http://noxx.penya.de/ruby-attachments.txt
This is the "main class" which was the binary in my first post. This
class handles the upload (payload) and creates subclasses depending on
the mimetyp.

If e.g. an image was uploaded it builds this class:
http://noxx.penya.de/ruby-images.txt
Images have some more attributes as width/height in the database table
so it's possible to search through them.

The general binary class for all other or - in my case also the image
file itself and the created thumbnail - is represented by this class:
http://noxx.penya.de/ruby-binaries.txt
Binaries handles all files and also the deletion if something is
destroyed.

Thus, the binary can belong directly to the attachment or upload itself
if the mimetyp is not recognized or as the "data" of the image.

I splitted image/binary and so on because if I save it all in one table
I have many NULL-rows and it's hard to handle.

But it should be easy to extend, too...

In the end I can call @attachments.all, get back all the uploaded files
as the specific class and let the render choose which view to display.

I hope I could give you an impression of my solution and maybe you have
some suggestions what would be good to improve.

Thanks for your time and again for your reply, too.
Greetings.