Paperclip Documentation

repository·main·Indexed 27 days ago

https://github.com/thoughtbot/paperclip

A library for attaching files to ActiveRecord models. Now deprecated in favor of Rails' ActiveStorage, with migration guidance provided for existing projects and a recommendation to use the maintained kt-paperclip fork for continued support. Includes documentation on ImageMagick configuration, attachment validations, storage adapters (File, S3, Fog), custom processors, and model configuration using has_attached_file.

Tokens
10.3K
Snippets
31
Records
53
Agent score
94%

What's inside Paperclip

  1. Apply ActiveStorage database migrations

    main

    To prepare your database for ActiveStorage, follow these steps:

    1. Add the mini_magick gem to your Gemfile.
    2. Ensure config/application.rb requires the ActiveStorage engine:
    require "active_storage/engine"
    1. Run the installation command:
    rails active_storage:install
    # config/application.rb
    require "active_storage/engine"
  2. Install Paperclip gem

    main

    Add Paperclip to your Gemfile to use it in your application.

    To use a specific version:

    gem "paperclip", "~> 6.0.0"

    To use the latest code from the master branch:

    gem "paperclip", git: "git://github.com/thoughtbot/paperclip.git"
  3. Use dynamic configuration for styles and processors

    main

    You can pass lambdas or Procs to styles and processors to determine configuration at runtime based on the specific model instance.

    # Dynamic Styles based on instance state
    class User < ActiveRecord::Base
      has_attached_file :avatar, styles: lambda { |attachment| { thumb: (attachment.instance.boss? ? "300x300>" : "100x100>") } }
    end
    
    # Dynamic Processors based on instance state
    class User < ActiveRecord::Base
      has_attached_file :avatar, processors: lambda { |instance| instance.processors }
      attr_accessor :processors
    end
  4. Create custom attachment processors

    main

    You can implement custom processors for tasks like watermarking, compression, or encryption.

    To create a processor:

    1. Define the class within the Paperclip module.
    2. Inherit from Paperclip::Processor.
    3. Implement a make method that returns a File.

    Files located in lib/paperclip or lib/paperclip_processors are automatically loaded. Use the :processors option in has_attached_file to specify them. Processors are executed in the order defined; each successive processor receives the output of the previous one and the same options hash from the :styles definition.

    # Example of applying a custom processor
    has_attached_file :scan, styles: { text: { quality: :better } },
                             processors: [:ocr]
  5. Configure Paperclip storage path for parallel tests

    main

    When running tests in parallel, the default storage path can cause file collisions. Use ENV['TEST_ENV_NUMBER'] to create unique paths for each test process.

    if ENV['PARALLEL_TEST_GROUPS']
      Paperclip::Attachment.default_options[:path] = ":rails_root/public/system/:rails_env/#{ENV['TEST_ENV_NUMBER'].to_i}/:class/:attachment/:id_partition/:filename"
    else
      Paperclip::Attachment.default_options[:path] = ":rails_root/public/system/:rails_env/:class/:attachment/:id_partition/:filename"
    end
  6. Configure Capistrano for Paperclip deployments

    main

    To ensure attachments survive deployments, symlink the public/system directory in your config/deploy.rb:

    set :linked_dirs, fetch(:linked_dirs, []).push('public/system')

    You can also automate the generation of missing styles by adding a task to your Capistrano deployment flow that runs rake paperclip:refresh:missing_styles.

    namespace :paperclip do
      desc "build missing paperclip styles"
      task :build_missing_styles do
        on roles(:app) do
          within release_path do
            with rails_env: fetch(:rails_env) do
              execute :rake, "paperclip:refresh:missing_styles"
            end
          end
        end
      end
    end
    
    after("deploy:compile_assets", "paperclip:build_missing_styles")
  7. Use the kt-paperclip fork for continued support

    main
    Since Paperclip is deprecated, you can use kt-paperclip, a maintained fork of the original library. This is recommended for existing projects that are not yet ready to migrate to ActiveStorage.
  8. Copy Paperclip database metadata to ActiveStorage

    main

    Since Paperclip stores metadata directly on the associated object's table and ActiveStorage uses active_storage_blobs and active_storage_attachments tables, you must write a migration to convert the data.

    Depending on your database, use the appropriate command to retrieve the last inserted ID within your migration:

    • Postgres: get_blob_id = 'LASTVAL()'
    • MariaDB: get_blob_id = 'LAST_INSERT_ID()'
    • SQLite: get_blob_id = 'LAST_INSERT_ROWID()'

    Note: The migration provided in the documentation uses prepared statements for active_storage_blob_statement and active_storage_attachment_statement to ensure data integrity during the transfer.

  9. Migration guidance for deprecated Paperclip

    main

    Paperclip is deprecated. For new projects, use Rails' built-in ActiveStorage.

    For existing projects using Paperclip, you have several options:

    1. Migrate to ActiveStorage: Consult the official migration guide or use alternative tutorials like the one used by Doorkeeper.
    2. Use a maintained fork: Use kt-paperclip, which is an ongoing fork of Paperclip maintained by Kreeti.

    Note: The original Paperclip repository is no longer accepting pull requests (except for the migration guide) and issues are only used as a discussion forum.

  10. Migrate local files to ActiveStorage storage directory

    main

    Paperclip and ActiveStorage use different directory structures. Paperclip typically uses public/system/..., while ActiveStorage uses a nested structure under storage/ based on the blob's key.

    To move local files, use a script that calculates the destination directory using the first two and next two characters of the blob key.

    #!bin/rails runner
    
    class ActiveStorageBlob < ActiveRecord::Base
    end
    
    class ActiveStorageAttachment < ActiveRecord::Base
      belongs_to :blob, class_name: 'ActiveStorageBlob'
      belongs_to :record, polymorphic: true
    end
    
    ActiveStorageAttachment.find_each do |attachment|
      name = attachment.name
    
      source = attachment.record.send(name).path
      dest_dir = File.join(
        "storage",
        attachment.blob.key.first(2),
        attachment.blob.key.first(4).last(2))
      dest = File.join(dest_dir, attachment.blob.key)
    
      FileUtils.mkdir_p(dest_dir)
      puts "Moving #{source} to #{dest}"
      FileUtils.cp(source, dest)
    end
  11. Handle validation order conflicts with attachments

    main

    If you have other validations that depend on the order of assignment, prevent the automatic assignment of the attachment during mass assignment (e.g., via book_params). Instead, assign the attachment manually after the model is initialized to ensure validations run in the correct sequence.

    class Book < ActiveRecord::Base
      has_attached_file :document, styles: { thumbnail: "60x60#" }
      validates_attachment :document, content_type: "application/pdf"
      validates_something_else # Other validations that conflict with Paperclip's
    end
    
    class BooksController < ApplicationController
      def create
        @book = Book.new(book_params)
        @book.document = params[:book][:document]
        @book.save
        respond_with @book
      end
    
    private
    
    def book_params
        params.require(:book).permit(:title, :author)
      end
    end
  12. Configure Paperclip storage adapters

    main

    Paperclip supports three built-in storage adapters:

    • File Storage: Default local filesystem storage.
    • S3 Storage: Requires the aws-sdk-s3 gem.
    • Fog Storage: Uses the Fog library.

    To use S3, add gem 'aws-sdk-s3' to your Gemfile and specify storage: :s3 in has_attached_file.