How can I change the basename when uploading images?

182 views
Skip to first unread message

jamesw

unread,
Oct 20, 2009, 6:16:12 PM10/20/09
to Paperclip Plugin
I would like to change the name of the actual image uploaded.

Example, say I uploaded an image called 21012009015436-1.jpg that I
want attached to my catalogue model I would like the image to actually
be called catalogue_icon.jpg

I assume that I need to set the basename variable somehow but I can't
figure out how to do this.
Any ideas?

Harmon

unread,
Oct 20, 2009, 7:47:41 PM10/20/09
to Paperclip Plugin
Hi James,

Assuming you had a model:

class MyImage < ActiveRecord::Base
has_attached_image :attachment,
:path => ':rails_root/images/:filename'

# This works the same way in your case, too:
# :path => ':rails_root/images/:basename.:extension'
end

You could do the following:

file = File.new('/path/to/you/file/21012009015436-1.jpg')
my_image = MyImage.new
my_image.attachment = file
my_image.attachment_file_name = 'catalogue_icon.jpg'
my_image.save!

That will store your new image at:
"#{RAILS_ROOT}/images/catalogue_icon.jpg"

On save, it stores the file based on the path you give it.
In Paperclip::Store::Filesystem#flush_writes is where it saves the
file to
it's final destination using this command:

FileUtils.mv(file.path, path(style))

Whatever "path(style)" returns is the new filename. And if you use the
":filename"
or ":basename" interpolation variables in the :path, then it will use
the attachment_file_name
attribute as the name of the attachment.

Hope that helps :)

jamesw

unread,
Oct 21, 2009, 9:51:01 AM10/21/09
to Paperclip Plugin
Sorry, if this is a duplicate but my previous response was not posted
for some reason so I'm posting again
Firstly a big thanks to Harmon. This is what I was looking for.
I can't seem to make it work quite the way I want it to though

My model

has_attached_file :icon, :default_style => :thumb,
:styles => {:thumb => ["32x32>"]},
:storage => :Ftp,
:url => "/system/
catalogue/:id/:style/:basename.:extension",
:path => "/httpdocs/#{SiteDetail.get_url}/system/
catalogue/:id/:style/:basebname.:extension"

before_post_process :set_icon_name
protected
def set_icon_name
unless self.icon_file_name.empty?
self.icon_file_name = "catalogue_#{self.name}_icon"
end
end

This will generate the correct url so that image tags point to the
location and file name that I want them to with the amended file name
but the uploaded image still has the original file name so it seems
that the :path => ... does not take the new file name into account.

Maybe it's a timing issue and the before_post_process is too late in
the scheme of things to affect the path so any ideas on what event/
callback would work?

I've tried before_save event on the model but that had the same
effect.

Gorism

unread,
Oct 21, 2009, 12:04:07 PM10/21/09
to Paperclip Plugin
I was interested in customizing the name as well, and came across this
post: http://almosteffortless.com/2009/03/22/randomize-filename-in-paperclip/

This approach worked for me. I wasn't trying to randomize the
filename, just wanted to manipulate it prior to persistence. The
point is to get the filename the way you want, then call
instance_write with the filename as part of before_create.

Mark

jamesw

unread,
Oct 21, 2009, 3:01:48 PM10/21/09
to Paperclip Plugin
Thanks Gorism

That's cool.
It's the instance_write method that's done the trick

before_save :set_icon_name

protected

def set_icon_name
return if icon_file_name.nil?
if icon_file_name_changed?
self.icon.instance_write(:file_name, iconfname)
end
end

def iconfname
"catalogue_#{self.name}_icon#{File.extname(self.icon_file_name)}"
end

Using the before_save makes sure that updates to existing records as
well as new records get the amended file name

Works perfectly.
Thank's everyone :-)

Adam Grant

unread,
Oct 21, 2009, 3:12:56 PM10/21/09
to papercli...@googlegroups.com
Glad you got it working,

I should have mentioned instance_write, but I didn't realize that there was an extra instance variable it creates and also sets called @_icon_file_name. And turns out, the path(:style) actually calls instance_read(:filename), which reads from that same variable. My bad :)

From attachment.rb:
===============
    def instance_write(attr, value)
      setter = :"#{name}_#{attr}="
      responds = instance.respond_to?(setter)
      self.instance_variable_set("@_#{setter.to_s.chop}", value)
      instance.send(setter, value) if responds || attr.to_s == "file_name"
    end

    def instance_read(attr)
      getter = :"#{name}_#{attr}"
      responds = instance.respond_to?(getter)
      cached = self.instance_variable_get("@_#{getter}")
      return cached if cached
      instance.send(getter) if responds || attr.to_s == "file_name"
    end
===============
Cheers,
Adam
Reply all
Reply to author
Forward
0 new messages