Random File Name (part 2)

624 views
Skip to first unread message

Trevor Turk

unread,
Mar 12, 2009, 3:17:47 PM3/12/09
to Paperclip Plugin
I can't seem to post to the old thread about this, sorry!

http://groups.google.com/group/paperclip-plugin/browse_thread/thread/c8f58f0a4ef45d20

On Jan 5, 6:47 pm, Trevor Turk <trevort...@gmail.com> wrote:
> class Photo < ActiveRecord::Base
> has_attached_file :image # ...
>
> before_create :randomize_file_name
>
> def randomize_file_name
> extension = self.image_file_name.scan(/\.\w+$/).to_s.downcase
> self.image_file_name = "#{CGI::Session.generate_unique_id}#
> {extension}"
> end
> end

This has stopped working for me since upgrading past 2.2.2, and I
can't figure out why (or how to work around it). I'm trying to
randomize the file name of an image before saving it, so if something
named "logo.gif" was uploaded it, it would be saved as
"cff11f9e59b215d0642f5d52a6a2bd71.gif" or whatever random string. The
problem is that setting image_file_name before_create used to
accomplish this. Now, the files are still uploaded with their "real"
name, and I can't seem to work around it.

Any help would be very much appreciated!

Thanks,
- Trevor

Jonathan Yurek

unread,
Mar 12, 2009, 3:56:36 PM3/12/09
to papercli...@googlegroups.com
Trevor,

Could you try making this a before_post_process filter?

before_post_process :randomize_file_name
def randomize_file_name
extension = File.extname(image_file_name)
self.image_file_name =
"#{CGI::Session.generate_unique_id}#{extension}"
end

I believe this will do what you want it to do.
--
Jonathan Yurek, Founder and CTO
thoughtbot, inc.
organic brains. digital solutions.

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

Trevor Turk

unread,
Mar 12, 2009, 4:27:16 PM3/12/09
to Paperclip Plugin
On Mar 12, 2:56 pm, Jonathan Yurek <jyu...@thoughtbot.com> wrote:
> Trevor,
>
> Could you try making this a before_post_process filter?
>
> before_post_process :randomize_file_name
> def randomize_file_name
>    extension = File.extname(image_file_name)
>    self.image_file_name =  
> "#{CGI::Session.generate_unique_id}#{extension}"
> end
>
> I believe this will do what you want it to do.

Thanks very much for the reply, but this doesn't work :(

I've been digging through the commits from 2.2.2 to current, and I
just can't seem to figure out what changed that would impact this. The
image_file_name (in my case) is being set to the correct random hash,
but the file (being uploaded to s3) has the original name.

If you've got any other ideas, I'm all ears. Otherwise, I'll post back
here if/when I figure something out!

- Trevor

Jonathan Yurek

unread,
Mar 12, 2009, 4:51:55 PM3/12/09
to papercli...@googlegroups.com
Really? That's odd. Can you paste your whole has_attached_file? The
name of the S3 key is the path, based on the path attribute. If you
have :basename in there it should be using the image_file_name
attribute.

Trevor Turk

unread,
Mar 12, 2009, 5:14:21 PM3/12/09
to Paperclip Plugin
On Mar 12, 3:51 pm, Jonathan Yurek <jyu...@thoughtbot.com> wrote:
> Really? That's odd. Can you paste your whole has_attached_file? The  
> name of the S3 key is the path, based on the path attribute. If you  
> have :basename in there it should be using the image_file_name  
> attribute.

http://pastie.org/414608.txt

Yeah, I'm confused as well. I hope I'm not making some silly mistake,
but I just can't seem to find anything. The image_file_name is being
set as expected in the database, and the views are looking for the
right file. It's just that the uploading to s3 seems to be using the
"real" file name. Here's part of the development logs that shows the
upload.

http://pastie.org/414611.txt

Note the "costco" part in the filename - the image I'm saving is
called "costco.png".

Thanks again for your reply. Let me know if there's any other
information that might help!

- Trevor

mat3001

unread,
Mar 16, 2009, 6:53:10 AM3/16/09
to Paperclip Plugin
Hi Trevor,
I am currently stuck with the same problem.
Have you figured out how to make paperclip actually save to s3 with
the random filename in the mean time?

cheers
mat

Jonathan Yurek

unread,
Mar 16, 2009, 8:54:41 AM3/16/09
to papercli...@googlegroups.com
Trevor and mat,

I believe I found the culprit, and its name is memoization. When the
file is set, a caching instance variable on Paperclip::Attachment
holds the file name.

Modifying my example from before, this should work:

before_post_process :randomize_file_name
def randomize_file_name
extension = File.extname(image_file_name)
self.image.instance_write(:file_name,
"#{CGI::Session.generate_unique_id}#{extension}")
end

It's a bit ungainly, but I'm certain this will work where the other
failed.

mat3001

unread,
Mar 16, 2009, 9:35:58 AM3/16/09
to Paperclip Plugin
Thanks for looking into the Issue, Jonathan.
I was able to get it to work with your example.

Now I will jush have to figure out how to limit the post-processing to
the newly uploaded file.
That's because I use has_attached_file two times in one model. I guess
the current solution only works reliably on one paperclip attachment
per model.

Thanks!
mat

Trevor Turk

unread,
Mar 16, 2009, 6:38:37 PM3/16/09
to Paperclip Plugin
On Mar 16, 7:54 am, Jonathan Yurek <jyu...@thoughtbot.com> wrote:
> I believe I found the culprit, and its name is memoization. When the  
> file is set, a caching instance variable on Paperclip::Attachment  
> holds the file name.

Amazing. Thank you so much for your help with this issue. I was
actually able to get your code example working with a before_create
filter, which works better for me in my tests because I'm stubbing out
the post_process method to get my tests running faster:

http://almosteffortless.com/2009/03/12/speeding-up-paperclip-tests-by-a-lot/

Thanks again. I'm a happy dude now :)

- Trevor

Kennon Ballou

unread,
May 15, 2009, 4:05:26 AM5/15/09
to Paperclip Plugin
By the way, CGI::Session.generate_unique_id no longer works with Rails
2.3.2, you need to use ActiveSupport::SecureRandom.hex.

I just used this successfully to randomize the filename:

before_post_process :randomize_image_file_name

def randomize_image_file_name
extension = File.extname(image_file_name)
self.image.instance_write(:file_name, "#
{ActiveSupport::SecureRandom.hex.first(8)}#{extension}")
end

Kennon Ballou
| Angry Turnip, Inc.
> http://almosteffortless.com/2009/03/12/speeding-up-paperclip-tests-by...

Kennon Ballou

unread,
May 15, 2009, 6:40:49 AM5/15/09
to papercli...@googlegroups.com
I just wrote this initializer mixin for a project of mine to randomize
attachment filenames (I put it in
config/initializers/randomizes_attachment_file_name.rb):

module Paperclip
module ClassMethods
def randomizes_attachment_file_name name
before_post_process :"randomize_#{name}_file_name"

define_method :"randomize_#{name}_file_name" do |*args|
self.send(name).queue_existing_files_for_delete
extension = File.extname(self.send(:"#{name}_file_name"))
self.send(name).instance_write(:file_name,
"#{ActiveSupport::SecureRandom.hex}#{extension.downcase}")
end
end
end

class Attachment
def queue_existing_files_for_delete #:nodoc:
@queued_for_delete += [:original, *@styles.keys].uniq.map do
|style|
path(style) if exists?(style)
end.compact
end
end
end


This lets me do the following:

class User < ActiveRecord::Base
has_attached_file :avatar
randomizes_attachment_file_name :avatar
end


I had to add the queue_existing_files_for_delete method, because when
reprocessing the old filenames would get forgotten and then never removed.

I have only used this in Rails 2.3.2, I'm not sure if the
ActiveSupport::SecureRandom.hex works in previous versions - you used to
use CGI::Session.generate_unique_id.

I don't have any tests for this yet, and there are probably better ways
to do some of this, but I thought this might be useful for some of you.

Reply all
Reply to author
Forward
0 new messages