Topic: attachment_fu file rename / change filename

I've been looking for a solution to change the filenames of the uploaded files and came across the great tutorial at http://the.railsi.st/2007/8/21/how-to-c … ile-names/  but it was not what i was exactly looking for. I had issues with viewing the saved files because the thumbnail property does not exist for the new attachment etc.

I'm posting what I did and it changes the filenames to what ever we specify.. Works for me, and hopefully it will work for someone else as well.. smile


class Photo < ActiveRecord::Base
    #Options for has_attachment
    has_attachment    :content_type => :image,
                                          :storage => :file_system,
                                          :size => 1.kilobyte .. 10.megabytes,
                                          :resize_to => '500>',
                            :thumbnails => { :thumb => '125' },
                                          :path_prefix => 'public/images/product_pics',
                            :processor    => 'MiniMagick'
  validates_as_attachment

  belongs_to  :product

  #Filename changing stuff, these methods resides in attachement_fu plugin files..
  #and we are just modifying them to fit our needs and putting them in our model
  #so other models will not be effected
  def full_filename(thumbnail = nil)
    file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix]
    @thumb = self.thumbnail unless (@thumb = thumbnail) #checks if thumbnails info already exist
    File.join(RAILS_ROOT, file_system_path, self.product.code, thumbnail_name_for(@thumb, self.product.code))
  end

  def thumbnail_name_for(thumbnail = nil, asset = nil)
    suffix = "_#{thumbnail}" unless thumbnail.blank?  #sets suffix by the name of the thumbnail set in has_attachment options
    extension = filename.scan(/\.\w+$/) # extracts extension
    return "#{asset}#{suffix}#{extension}" # change the filename to fit your needs
  end
 
  before_thumbnail_saved do |record, thumbnail|
      thumbnail.product_id = record.product_id
  end

end

Last edited by buddhi (2008-03-04 03:36:22)

Re: attachment_fu file rename / change filename

Is it possible to do this with a pdf document where there is no thumbnail?

Re: attachment_fu file rename / change filename

should be able to.. since this changes filename and the thumbnail name as well.. but i'm also a noob and never get the chance to dig deeper into attachment_fu

However i found this method to be messy/flowed and couldn't fix it completely, since i had to stick to the overall project deadlines.. This renames the file stored in the system, yet keep the original file name in the database.. the filename will be built during the execution to match the defined renaming method. if we use random number for the file name, we are doomed because file name will be different every time it calculate the file name sad

Finally i settled for this.. it renames the file with a key made with time and stores the same name in the db as well.. check the comments in the code for explanation on file naming.

    def uploaded_data=(file_data)
        return nil if file_data.nil? || file_data.size == 0
        self.content_type = file_data.content_type
        extension = file_data.original_filename.slice(/\.\w+$/)
        #
        # Unfortunately we just cant use an instance variable here..
        # I couldn't find a way to access a variable in a super class
        # i think accessing a super class was the issue.
        # However I settled for a random filename smile
        # you can use a fixed prefixes and suffixes to customize the file name
        #
        self.filename  =    "your_prefix" + Digest::SHA1.hexdigest(Time.now.to_s) + "your_suffix" + extension
        #
        #
        File.extname(file_data.original_filename) if respond_to?(:filename)
        if file_data.is_a?(StringIO)
            file_data.rewind
            self.temp_data = file_data.read
        else
            self.temp_path = file_data.path
        end
    end
end

Last edited by buddhi (2008-05-03 00:35:27)

Re: attachment_fu file rename / change filename

Sorry for my late answer, but your solution works perfect! Thanks for that, could you help me with 1 last thing :
If I upload something, the script generates a folder 0000 and within this folder another folder with the id, how can I upload something without all this?

This is my code

has_attachment :storage => :file_system, :path_prefix => 'public/files', :content_type => 'application/pdf'

Edit : do you maybe know how I can upload 2 files at 1 time?

Last edited by reyntjensw (2008-05-21 09:57:16)

Re: attachment_fu file rename / change filename

1. A quick reply.. This should get the path issue fixed. If this doesn't help, please post detailed code you used in the model. I'm not a guru, but will try to help.. smile

#Changes the folder structure
  def full_filename(thumbnail = nil)
  file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix]
  File.join(RAILS_ROOT, file_system_path, self.product.id.to_s, thumbnail_name_for(thumbnail))
end

2. As far as I know you'll have to upload them separately.. the model handles one file at a time. If you are thinking about ajax "like" uploading function,  its possible. I've done something similar with my app.

Last edited by buddhi (2008-05-21 10:10:09)

Re: attachment_fu file rename / change filename

this doesn't work look this I have:

class Inhoud < ActiveRecord::Base
  has_attachment :storage => :file_system, :path_prefix => 'public/files', :content_type => 'application/pdf'
 
    def uploaded_data=(file_data)
       return nil if file_data.nil? || file_data.size == 0
       self.content_type = file_data.content_type
       extension = file_data.original_filename.slice(/\.\w+$/)
       #
       # Unfortunately we just cant use an instance variable here..
       # I couldn't find a way to access a variable in a super class
       # i think accessing a super class was the issue.
       # However I settled for a random filename smile
       # you can use a fixed prefixes and suffixes to customize the file name
       #
       self.filename  =    Digest::SHA1.hexdigest(Time.now.to_s)  + extension
       #
       #
       File.extname(file_data.original_filename) if respond_to?(:filename)
       if file_data.is_a?(StringIO)
         file_data.rewind
         self.temp_data = file_data.read
       else
         self.temp_path = file_data.path
       end
     end
end

This is my model code.

What I'd like to change is this files/0000/0001/filename to files/filename

Thanks in advance Buddhi:)

Re: attachment_fu file rename / change filename

Your model doesn't seems to modify the full filename, I just deleted the comments in your posted code for clarity. Just insert the code I've put below the comments and see if it works. Its the same code I've posted in my previous post. I've just put it inside your model code..

class Inhoud < ActiveRecord::Base
#START: YOUR MODEL CODE
  has_attachment :storage => :file_system, :path_prefix => 'public/files', :content_type => 'application/pdf'

  def uploaded_data=(file_data)
    return nil if file_data.nil? || file_data.size == 0
    self.content_type = file_data.content_type
    extension = file_data.original_filename.slice(/\.\w+$/)

    self.filename  =    Digest::SHA1.hexdigest(Time.now.to_s)  + extension
   
    File.extname(file_data.original_filename) if respond_to?(:filename)
    if file_data.is_a?(StringIO)
      file_data.rewind
      self.temp_data = file_data.read
    else
        self.temp_path = file_data.path
    end
  end

  # START: FOLDER STRUCTURE MODIFYING CODE
  # Did you try after adding the code below?
  #
  #Changes the folder structure
  def full_filename(thumbnail = nil)
    file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix]
    File.join(RAILS_ROOT, file_system_path, self.product.id.to_s, thumbnail_name_for(thumbnail))
  end
  #
  #END: FOLDER STRUCTURE MODIFYING CODE

#END: YOUR MODEL CODE
end

Re: attachment_fu file rename / change filename

I did left it out when I copied my code, could you tell me what self.product.id.to_s stands for?

Re: attachment_fu file rename / change filename

Mea culpa, my attachment model belongs to Product model.. sorry for the mistake sad

self.product.id.to_s is there to covert the product_id integer into a string..

This might work..

def full_filename(thumbnail = nil)
  file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix]
  File.join(RAILS_ROOT, file_system_path, thumbnail_name_for(thumbnail))
end

Re: attachment_fu file rename / change filename

Great that works, could you maybe help me with 1 more thing, you told me in a previous post that you made an ajax upload "script", could you post this?
Maybe I can use this with the multiple fileuploads.

Thanks for your help

Re: attachment_fu file rename / change filename

Sure.. But my code is old and really messy..did it at the time i started learning rails/ruby. Too lazy to clean it up as well wink I think you'd benefit from a fresh start. Its not very complex anyway

These links will be helpful on getting started
http://wiki.rubyonrails.org/rails/pages … +to+Parent
http://www.caboo.se/articles/2007/4/2/ajax-file-upload

We cannot upload attachments using an ajax request, however we can give a hidden iframe as a target so the user will not see page getting refreshed since response it directed toward that hidden iframe. And the respond_to_parent sends the ajax request to parent of iframe and you can show an uploaded thumbnail or file size there "mimicking" a seamless ajax upload..

good luck & keep me posted if you need any help, i'll try to help as time permits smile

Last edited by buddhi (2008-05-21 11:24:37)

Re: attachment_fu file rename / change filename

Here's a great walkthrough for the responds_to_parent method, from May 2007 but works fine in Rails 2.1:
AJAX file uploads in Rails using attachment_fu and responds_to_parent (Khamsouk Souvanlasy)

Last edited by Train (2008-09-05 09:23:17)

Re: attachment_fu file rename / change filename

Hi there, I've got a little adition to this question.

Is it possible to change the upload dir with a variable?

I'll give an example to explain what I'd like to say.

For example
The basic dir is /public/files
Within this folder are 2 other dirs, dir a and dir b.

Is it possible to change to upload dir to /public/files/a/ when I set is as default dir in my view? (for example)?

Last edited by reyntjensw (2008-10-13 13:55:05)

Re: attachment_fu file rename / change filename

So I've been struggling with this for a couple of days now, going on a week.  Everything posted here is great but like everyone else I'm trying to do something just a tad bit differently.

In my case I'm going to have several Model's that are photoable and when processing photos I would like to rename them to Type_id_originalFileName.ext - that is the photoable object type, id and finally the original filename (or some other unique name for that matter).

I've taken the information here and elsewhere and constructed a Photo model that belongs to photoable, is polymorphic, and finally writes the files to size directories beneath my uploads/photos directory.

I'm about to pour myself a cold Pepsi (plug!) and try to understand this completely but I have yet to wrap my mind around exactly what's going on when I upload a file.  However, in one case I was able to successfully rename the thumbnail file to what I wanted but I get the impression that each image is a new Photo model and therefore, given the way attachment_fu works, all the resized images have no photoable but rather a parent (the thumbnail).  I tried referencing the parent.photoable if it existed but only failed.

Dave K.

UPDATE: sidelined by the snow smile

ANOTHER UPDATE: It's crazy, I actually figured it out.  Posting code soon.

Last edited by davidklaw (2008-12-20 15:20:18)

Re: attachment_fu file rename / change filename

Attaching photos to multiple Model types, unique rename based on parent Model

This might appear to be a tad ugly - if anyone has suggestions please shout em out!

Photo.rb

belongs_to :photoable, :polymorphic => true
...

def full_filename(thumbnail = nil)
    file_system_path = (thumbnail ? thumbnail_class : self).attachment_options[:path_prefix]
    thumbnail ||= self.thumbnail
    subdir = thumbnail ? thumbnail.to_s : 'full'
    photo_parent = self.photoable || self.parent.photoable #
    thumb_id = self.parent ? self.parent.id.to_s : id
    File.join(RAILS_ROOT, file_system_path, subdir, thumbnail_name_for("#{photo_parent.type.to_s}_#{photo_parent.id.to_s}_#{thumb_id}"))
  end

def thumbnail_name_for(thumbnail = nil)
  return filename if thumbnail.blank?
  ext = nil
  filename.gsub /\.\w+$/ do |s|
    ext = s; ''
  end
  ext.sub!(/gif$/, 'png') if attachment_options[:processor] == "ImageScience"
  "#{thumbnail}#{ext}" # EDIT: removed basename
end

# Save the new filename on the record
def before_save
  self.filename = full_filename(self)
end


I had to override 2 methods from attachment_fu.rb.  We'll start with the one furthest down the chain here, thumbnail_name_for.  The only difference from the base class was the removal of the basename variable which I no longer needed.  The resulting thumbnail will be whatever is passed in as an argument.

Most of the work is in full_filename.  It's here that I look for either a Photo's "parent", which is either the parent thumbnail OR the parent photoable object.  That way I can look up the chain and generate a new filename passed on the singular image's photoable parent object.  To make the image names unique I use the thumbnail (or parent) image's unique id.  I figure that by naming it in this way I can always break down the name to determine the parent (I don't know why I would but who knows?).

The app, given my other code changes, will do the following if I were to upload an image.

public/uploads/photos/full/User_123_1.jpg
public/uploads/photos/small/User_123_1.jpg
public/uploads/photos/medium/User_123_1.jpg
public/uploads/photos/large/User_123_1.jpg

Does it make more sense to create user folders?


Dave K.

Last edited by davidklaw (2008-12-21 19:57:05)

Re: attachment_fu file rename / change filename

6 months too late, but you should check the limits of your file system before dumping thousands of files into one directory.  There are theoretical maximums as well as operational ones.

The :partition option is turned on by default resulting in dirs like /0000.

-Joe

Re: attachment_fu file rename / change filename

I think you may have been looking at my registration date smile  You're actually only a little over a month late haha but I do appreciate the advice and will take this in to consideration.

Dave K.

Re: attachment_fu file rename / change filename

Great that works, could you maybe help me with 1 more thing, you told me in a previous post that you made an ajax upload "script", could you post this?
Maybe I can use this with the multiple fileuploads  Batch File Renamer.