Paperclip and Inheritance (STI)

435 views
Skip to first unread message

nodoubtarockstar

unread,
May 28, 2009, 3:38:09 PM5/28/09
to Paperclip Plugin
I have been using attachment_fu for years and just moved one of my
more complex apps over to using Paperclip. I have a generic
"attachments" table, which I've been using for STI that has a type
(i.e. Photo, Video, Document, etc.). There may be a way to maintain
this using Paperclip, but the issue I have is with the column name
having the attachment name prefix. That's actually sort of an unfair
assumption that anyone would want that prefix there, where
attachment_fu simply requests the columns be named "content_type" or
"filename". To have to prepend with "attachment" means that I now
break all of my inherited models, since there isn't a column for
photo_file_name or video_file_name (and I fully intend to keep it
that way). So I guess two things: A) Is it possible to do what I'm
trying to do easily (right now I have attr_accessors and before_saves
on each of the inherited models that just set the appropriate
attachment attributes so the table gets updated correctly) but even
that doesn't work in a lot of cases, and it's a lot of extra code to
maintain .. and B) if not, why wouldn't the column names have been
abstracted so that developers can dictate how their app should be run?
Food for thought possibly...

Regards, Jen

Kennon Ballou

unread,
May 28, 2009, 3:53:06 PM5/28/09
to papercli...@googlegroups.com
I used attachment_fu for years as well before switching to paperclip,
and actually I find paperclip to offer MORE flexibility to the developer.

To do what you're wanting to do, just do your STI in your model and then
call your file attachment 'file' or 'attachment':

class File < ActiveRecord::Base
# calling this File might be a namespace conflict, but you should get
the point
has_attachment :file
end

class Video < File
end

class Document < File
end

Then you can simply do

document.file.url
video.file.url

etc.

The fact that paperclip doesn't "take over" the model actually makes it
more useful to me, once I got my head around it - you have alot more
flexibility with the model without worrying about the attachment. I used
to have problems with attachment_fu when I wanted a model that sometimes
didn't have the attachment, and the validations would fail because there
was no file attached, etc.

But in the end, paperclip != attachment_fu - there are probably reasons
to use one or the other. If paperclip isn't doing it for you, stick with
attachment_fu :-)

| Kennon Ballou
| Angry Turnip, Inc.

nodoubtarockstar

unread,
May 28, 2009, 4:15:38 PM5/28/09
to Paperclip Plugin
That kind of makes sense, but it doesn't actually imply STI in that
case... it's almost an association at that point....

In other words, with attachment_fu, I was able to simply say:

class Photo < Attachment
has_attachment
end

Then when I want to access attrs on a photo, it's as simple as:
photo.public_filename or photo.content_type

Whereas, now to have to say photo.attachment (which I just tested and
it works like you said) seems a bit clunky, since really the photo IS
the attachment... and thus, I should be able to say:

photo.url, not photo.attachment.url

Not to mention the fact, that I actually do need to declare different
types of validations, styles, paths, etc within each model..

class Photo < Attachment
has_attached_file :photo, styles => { :thumb => '200x200>', :large
=> '600x600>' }
validates_attachment_content_type :photo, :content_type => ['image/
pjpeg','image/x-png'], :message => "invalid type"
validates_attachment_size :photo, :less_than => 4.megabytes
end

class Video < Attachment
has_attached_file :video
end

I would love to see them remove the restrictive
<attachment>_column_name requirements, and use something more generic.

Thanks for the reply! :)

Kennon Ballou

unread,
May 28, 2009, 4:18:24 PM5/28/09
to papercli...@googlegroups.com
Well, the entire point of paperclip is that it's just like a real
paperclip just clips a note or something else to a document - it isn't
the document itself.

If all you are doing is having objects that are the attachments
themselves, then you are probably better off using attachment_fu :)

nodoubtarockstar

unread,
May 28, 2009, 4:19:43 PM5/28/09
to Paperclip Plugin
Actually, just one more note:

You're right about Paperclip not taking over the model, and in this
case, that's exactly what I want it to do. :D Generally, on other
applications I've built since Paperclip, I've loved the simplicity...
but in this case, it's what I needed, and now I've dumped
attachment_fu because for the most part, it's pretty frustrating on
some levels, so maybe I'll just revert back. :)

Thanks again.

On May 28, 1:53 pm, Kennon Ballou <ken...@angryturnip.com> wrote:

Matt Jankowski

unread,
May 28, 2009, 4:22:22 PM5/28/09
to papercli...@googlegroups.com
What requirement prevents you from renaming your columns?

-Matt

nodoubtarockstar

unread,
May 28, 2009, 4:28:59 PM5/28/09
to Paperclip Plugin
Matt,

I'm not sure what you're getting at...

Nonetheless, all of the documentation points to the expected column
names in the format of <attachment>_column_name. If you have a better
suggestion, or an undocumented method of changing this, I'd love to
hear it.

But at this point, even from what Kennon has said, it appears that
Paperclip isn't going to do what I need anyhow structure-wise.

Matt Jankowski

unread,
May 28, 2009, 4:33:34 PM5/28/09
to papercli...@googlegroups.com

I'm not implying anything sinister, I'm just curious about the
requirement that prevents the rename - because that's probably the
easiest way to migrate to paperclip in this case...

There are tons of good reasons to not be able to rename the column
(legacy, other apps, etc), just wanted to make sure that it's totally
ruled out.

-Matt

nodoubtarockstar

unread,
May 28, 2009, 4:48:35 PM5/28/09
to Paperclip Plugin
So just to get you up to speed, my personal/business requirement is
that I have 5 different types of attachments and a single polymorphic
table to rule them all. Something like:

owner_type (i.e. PressRelease, User, Event, Group, etc.)
owner_id
type (Photo, Video, Audio, etc.)
filename
size
etc...

there are several reasons for it being poly and several reasons for
using the inheritance...

So for me to name the columns according to the attachment type doesn't
really work.

My migration attempt just simply changed filename, size, and
content_type to:

attachment_file_name
attachment_file_size
attachment_content_type

but when I try to do Photo.new params[:photo] (where :photo includes
the upload), I get an error: no attr_accessor photo_file_name (which
makes sense, but implies that I'm required to have a photo_file_name
on my model somewhere)

I could take Kennon's approach where a Photo basically "has an"
attachment, but I just didn't like that method for this particular
project, I like the idea of the photo "being" the attachment.

Maybe I went about it wrong, and if someone offered a solution, that
would be awesome, but so far I've been tinkering with this all day to
no avail.

Matt Jankowski

unread,
May 28, 2009, 5:06:55 PM5/28/09
to papercli...@googlegroups.com

Yeah, Paperclip definitely separates the objection/relational/
association concepts from the attachment/attribute concepts.

So, if you say a user has many attachments (photos, videos, whatever)
- you need an Attachment model from a data modeling perspective. Once
that's defined, you can give that AR::Base model an attribute
(:file, :photo, :image, etc) which is meant to handle the actual
uploaded file/attribute, on that record.

It is a bit weird to conceptualize, because you basically just want a
"shell model" which does nothing more but proxy down to the file
attribute -- but when you start thinking about it it's definitely two
different responsibilities (the relational has many association, and
the file attachment attribute).

I think you could do something like...

User (id, name, ...)
Event (id, title, ...)
Attachment (id, owner_type, owner_id, type, media_file_name,
media_content_type, media_file_size)
Photo < Attachment
Video < Attachment

Which would get you @photo.media.url and so on.

I think the STI and polymorphic associations don't really limit your
ability to use paperclip, but they do make naming/planning a little
more complex to think about than use cases w/out either of those things.

-Matt

Jonathan Yurek

unread,
May 28, 2009, 9:13:32 PM5/28/09
to papercli...@googlegroups.com
Hello,

The usage of paperclip is different from attachment_fu in that in
paperclip the attachment is just like any other attribute that has
more to it, like a Date. Attachment_fu makes a whole nother table in
order to store its data while paperclip keeps the attachment data in
the record it's attached to. Therefore, it's not only not an unfair
assumption to add the attachment name to the columns, it's absolutely
necessary in order to support more than one attachment on a class.

If I were going to recommend a course of action, I would advise you to
name your attachments the same in each class. Both Photo and Video
class would have, say, a :file or an :attachment attachment. While
this gives some not-so-nice names for either the columns or the
attachment itself, it would be sufficiently generic to be put into
both classes and with their own validations.
--
Jonathan Yurek, Founder and CTO
thoughtbot, inc.
organic brains. digital solutions.

617.482.1300 x114
http://www.thoughtbot.com/

nodoubtarockstar

unread,
May 28, 2009, 9:37:08 PM5/28/09
to Paperclip Plugin
"it's absolutely necessary in order to support more than one
attachment on a class" is a matter of opinion. I am a firm believer in
not class-scoping column names unless absolutely vital, instead I'm a
proponent of keeping things abstracted. By that I mean for instance,
if a user can have a photo, I'd rather the photos be their own model
and table. In agile methods, this is the most practical way of
achieving the goal, since it makes photos mostly independent of a user
and able to belong to multiple models. If you decide you don't want
your users to have photos anymore, you just delete the photos table.
This practice would be standard for many things, not just
attachments... user can have a group, but you more than likely
wouldn't put a group_id foreign key on your user model. You would be
wise to create a join table. Then when you don't want groups anymore
delete the groups table, or when something about the association
between a user and a group changes, your join model handles it, not
your user model. I agree that attachment_fu and paperclip are not the
same thing, I've already come to that conclusion hours ago.

In my opinion, an attachment is an object, and to tie it so closely to
another model is not useful in my case, and I can probably come up
with a thousand cases where it is or isn't useful depending on
context. I'm not saying paperclip is wrong or bad by any means, just
that it seems to have been developed with the intent of keeping it
very tightly coupled with it's "attached" class is all -- it becomes
an attribute instead of an association. So, I've decided to stick w/
attachment_fu on this particular project since, in my opinion, my
class objects (video/photo/etc) ARE the attachments and my aim was to
keep it that way.

Another reason, which your point validates the negative of, is... what
if I have a business rule that says, show me all user photos? What
you're suggesting means that I have to fetch every user record and
then iterate over them grabbing the photo off each one. No thanks. My
project requires viewing lists of the different types of attachments,
regardless of the class that "owns" them -- it would be a severe pain
if I had to grab all the records for the several different classes
that can even have attachments, and then start figuring out, which
have videos vs. which have photos vs. which have documents, etc. With
my way, I can just say Video.all and it doesn't matter if the video
belongs to a news article, a group, a user, or an event, doing this
means I will have tons of video objects, of which I can manipulate as
attachments.

~ Jen

Kennon Ballou

unread,
May 29, 2009, 2:55:16 AM5/29/09
to papercli...@googlegroups.com
> Another reason, which your point validates the negative of, is... what
> if I have a business rule that says, show me all user photos? What
> you're suggesting means that I have to fetch every user record and
> then iterate over them grabbing the photo off each one. No thanks. My
> project requires viewing lists of the different types of attachments,
> regardless of the class that "owns" them -- it would be a severe pain
> if I had to grab all the records for the several different classes
> that can even have attachments, and then start figuring out, which
> have videos vs. which have photos vs. which have documents, etc. With
> my way, I can just say Video.all and it doesn't matter if the video
> belongs to a news article, a group, a user, or an event, doing this
> means I will have tons of video objects, of which I can manipulate as
> attachments.

Well, I guess I for one fail to see the issue here - if you want an
attachment to act as it's own object, then make an object that only has
the attachment. The only potential "drawback" is that you have to call
object.attachment.url instead of object.attachment_url. In fact, I think
this makes way more sense, especially for forms, etc, because then you
don't have to muck about with uploaded_data fields, you just treat the
file itself as an attribute.

There is very very little difference in the code here:

attachment_fu:
--------------

class Video
belongs_to :user
has_attachment
end

<% form_for :video, :html => {:multipart => true} do |f| %>
<%= f.file_field :uploaded_data %>
<%= f.submit %>
<% end %>

def create
@video = Video.new(params[:video])
...
end

Video.each {|v| v.public_filename }


paperclip:
----------

class Video
belongs_to :user
has_attachment :file
end

Video.each {|v| v.image.url }

<% form_for :video, :html => {:multipart => true} do |f| %>
<%= f.file_field :file %>
<%= f.submit %>
<% end %>

def create
@video = Video.new(params[:video])
...
end

Video.each {|v| v.file.url }

---

And the biggest benefit in my mind to paperclip is that I am not forced
to maintain the Picture object as just an attachment.

This was a real problem for the last site I used a_f with, as my object
started out as 'only' the attachment (in my case it was a banner ad),
but then it started to have to do more and more things (a block of html
instead of a picture), and then I started to have lots of problems with
validations because the image wasn't always there, etc. Paperclip has
made my life a whole lot easier and I like the syntax and paradigm much
better.

But, again, use the right tool for the job :-)

| Kennon Ballou
| Angry Turnip, Inc.
| Email: ken...@angryturnip.com
| AIM: kennon42 * ICQ: 5042686 * MSN: kennon...@hotmail.com

Kennon Ballou

unread,
May 29, 2009, 2:58:45 AM5/29/09
to papercli...@googlegroups.com
Er, whoops, in the paperclip example it should be:

> Video.each {|v| v.file.url }

NOT

> Video.each {|v| v.image.url }

(I was typing that out originally using a Picture/image metaphor but
then noticed you were talking about videos)


| Kennon Ballou
| Angry Turnip, Inc.

Reply all
Reply to author
Forward
0 new messages