Search code examples
ruby-on-railspapercliprails-migrationsrails-activestorage

Paperclip::Attachment - undefined method `attach'. Asset Migration Rake Task


I am currently migrating from Paperclip to Active Storage using this tutorial, as well as referencing the official guide.

Current roadblock is the rake task for migrating my assets.

This is the content of my lib/tasks/migrate_paperclip_assets.rake file:

desc 'Generates file names on AWS S3 and places them in their proper structure'
namespace :posts do
  task migrate_to_active_storage: :environment do
    Post.where.not(image_file_name: nil).find_each do |post|
      img_filename = post.image_file_name
      ext = File.extname(img_filename)

      image_url =
      "https://#{Rails.application.credentials.dig(:aws,
      :bucket_name)}/#{Rails.application.credentials.dig(:aws,
      :host_name)}/posts/images/000/000/#{post.id}/original/#{img_filename}"
      puts image_url
      post.image.attach(io: open(image_url),
                            filename: post.image_file_name,
                            content_type: post.image_content_type)
    end
  end
end

When I run this, I get the following error:

rake aborted!
NoMethodError: undefined method `attach' for #<Paperclip::Attachment:0x00000003170090> 
[...]

On the Rails migration guide, it clearly states to use this method attach here in the same format as I have done - not sure why this spews an error. I know for sure that the url works and I have successfully attempted to download the images.

Here are things I have tried that did not work:

  1. Attempted this accepted solution.
  2. The closest thing to attach I saw from the docs was assign method. But there were no handlers for dealing with the image file.
  3. I also have tried downloading the files in the same directory and uploading them using the same post.image.attach.

Even though the Paperclip Attachment Class itself does not have an attach method defined, there are a good number of repos on GitHub with code having similar format: user.avatar.attach(io: open(avatar_url), filename: user.avatar_file_name).

This is the content of my app/models/post.rb file:

class Post < ApplicationRecord
    belongs_to :user
    has_many :comments, dependent: :destroy
    has_many :likes, dependent: :destroy
    has_many :dislikes, dependent: :destroy
    attr_accessor :uploaded_image_for_io_adapters, :file_name, :top_text, :bot_text


    has_attached_file :image  

  validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
  validates_attachment :image, presence: true
  validates_presence_of :poster
    validates_presence_of :description
    validates :user, presence: true
    validates :user_id, presence: true
end

Lost and confused, if you could suggest an alternative to bypass having to use this attach method, or give me pointers as to what it is I might be doing wrong that would be great.

For context, Ruby version: 2.4.1, Rails: 5.2.1


Solution

  • I think that the solution is in the documentation you have shared.

    class Organization < ApplicationRecord
      # New ActiveStorage declaration
      has_one_attached :logo
    
      # Old Paperclip config
      # must be removed BEFORE to running the rake task so that
      # all of the new ActiveStorage goodness can be used when
      # calling organization.logo
      has_attached_file :logo,
                        path: "/organizations/:id/:basename_:style.:extension",
                        default_url: "https://s3.amazonaws.com/xxxxx/organizations/missing_:style.jpg",
                        default_style: :normal,
                        styles: { thumb: "64x64#", normal: "400x400>" },
                        convert_options: { thumb: "-quality 100 -strip", normal: "-quality 75 -strip" }
    end
    

    It looks like the has_attached_file has to be replaced by has_one_attached.

    Otherwise, image will use Paperclip instead of ActiveStorage (which has attach method).