ruby-on-railspaperclip

Mapping of filenames to paths using Ruby on Rails' paperclip


I do not know anything about Ruby on Rails, but I am involved with re-writing an application developed with it by someone else a while ago. I have access to the source code and, while I like to think I know programming (C/C++, etc.), I'm having difficulty trying to figure out Ruby on Rails. And I guess the reason why I can't figure it out is because the details of it is hidden within a library (paperclip).

(Short version: I want to match filenames in a database column with the physical location of files on disk.)

With my limited knowledge, I know the following...

The application has a Gemfile.gem with this entry: 'paperclip', '4.3.0'. I've looked at the development history of paperclip and realise that this is from April 2016. So, it seems pretty old...

I have a PostgreSQL database with fields such as:

And all of this matches the variables mentioned here in the documentation.

The values under attachment_file_name in the database are just filenames, with no paths.

On disk, the files are stored in directories such as attachments/000/003/335/original/abc.txt, which looks exactly like the example in the documentation. So, I guess I am fairly sure that paperclip is being used.

How does the filename translate to the above path?

And, more importantly, if I have a set of a few hundred files, I would like to print out the full path for each file. There are duplicates in the filename that result in different paths. So I guess the calculation (hash function?) is done using both the filename and maybe the contents of the file.

Can someone offer suggestions about how to do this and/or what in the code I should be looking for?

I guess my question is similar to this Issue in the repository, which pointed the author of that Issue to StackOverflow (of course, that was 7 years ago).

Thank you! Any help would be appreciated!


Solution

  • It's easier with an example:

    class User < ActiveRecord::Base
      has_attached_file :attachment
    
      validates_attachment_content_type :attachment, content_type: /\Aimage\/.*\z/
    end
    

    Attach a file:

    >> User.create!(attachment: File.open("avatar.png"))
      TRANSACTION (0.1ms)  begin transaction
      User Create (0.3ms)  INSERT INTO "users" ("attachment_file_name", "attachment_content_type", "attachment_file_size", "attachment_updated_at") VALUES (?, ?, ?, ?)  [["attachment_file_name", "avatar.png"], ["attachment_content_type", "image/png"], ["attachment_file_size", 8229], ["attachment_updated_at", "2023-12-01 05:14:12.369915"]]
      TRANSACTION (5.4ms)  commit transaction
    => #<User id: 1, attachment_file_name: "avatar.png", attachment_content_type: "image/png", attachment_file_size: 8229, attachment_updated_at: "2023-12-01 05:14:12.369915603 +0000">
    

    This is the default path where file is stored:

    >> Paperclip::Attachment.default_options[:url]
    => "/system/:class/:attachment/:id_partition/:style/:filename"
    
    $ ls public/system/**/*.png
    public/system/users/attachments/000/000/001/original/avatar.png
    
    public/
    system/
    users/       - :class        # `User.name.underscore.pluralize`
                                 # https://github.com/thoughtbot/paperclip/blob/main/lib/paperclip/interpolations.rb#L88
    
    attachments/ - :attachment   # pluralized attachment name
                                 #                     vvvvvvvvvv
                                 # `has_attached_file :attachment`
                                 # https://github.com/thoughtbot/paperclip/blob/main/lib/paperclip/interpolations.rb#L191
    
    000/000/001/ - :id_partition # id padded with zeros and split in 3 groups (9 digits total)
                                 # https://github.com/thoughtbot/paperclip/blob/main/lib/paperclip/interpolations.rb#L174
    
    original/    - :style        # "original" is default, this is what you've uploaded
                                 # https://github.com/thoughtbot/paperclip/blob/main/lib/paperclip/interpolations.rb#L197
    
    avatar.png   - :filename
    

    If you can only work from the database side

    sqlite> select * from users;
    +----+----------------------+-------------------------+----------------------+----------------------------+
    | id | attachment_file_name | attachment_content_type | attachment_file_size |   attachment_updated_at    |
    +----+----------------------+-------------------------+----------------------+----------------------------+
    | 1  | avatar.png           | image/png               | 8229                 | 2023-12-01 05:14:12.369915 |
    +----+----------------------+-------------------------+----------------------+----------------------------+
    
    public/
    system/
    users/       - :class        # most likely the same as table name
    
    attachments/ - :attachment   # attachment_file_name
                                 # ^^^^^^^^^^s
    
    000/000/001/ - :id_partition # padded id - you'll need to work that one out
    
    original/    - :style        # "original" - this is not in the db
    
    avatar.png   - :filename     # attachment_file_name