如何从重新归档迁移到ActiveStorage?

时间:2018-08-28 11:32:49

标签: ruby-on-rails rails-activestorage refile

有什么想法如何使用 Refile 将正在运行的项目迁移到新Rails的 Active Storage

任何人都知道有关如何执行此操作的教程/指南吗?

谢谢, 帕特里克

1 个答案:

答案 0 :(得分:1)

我在这里写了一篇关于它的简短文章,详细解释了这个过程: https://dev.to/mtrolle/migrating-from-refile-to-activestorage-2dfp

过去我将我的 Refile 附加文件托管在 AWS S3 中,所以我所做的是重构我的所有代码以使用 ActiveStorage。这主要涉及更新我的模型和视图以使用 ActiveStorage 语法。

然后我删除了 Refile gem 并将其替换为 ActiveStorage 所需的 gem,例如 image_processing gem 和 aws-sdk-s3 gem。

最后我创建了一个 Rails DB 迁移文件来处理现有文件的实际迁移。在这里,我使用 Refile 附件遍历模型中的所有记录,以在 AWS S3 中找到它们各自的文件,下载它,然后使用 ActiveStorage 附件再次将其附加到模型。

移动文件后,我可以删除旧的 Refile 数据库字段:

require 'mini_magick' # included by the image_processing gem
require 'aws-sdk-s3' # included by the aws-sdk-s3 gem

class User < ActiveRecord::Base
  has_one_attached :avatar
end

class MovingFromRefileToActiveStorage < ActiveRecord::Migration[6.0]
  def up
    puts 'Connecting to AWS S3'
    s3_client = Aws::S3::Client.new(
      access_key_id: ENV['AWS_S3_ACCESS_KEY'],
      secret_access_key: ENV['AWS_S3_SECRET'],
      region: ENV['AWS_S3_REGION']
    )

    puts 'Migrating user avatar images from Refile to ActiveStorage'
    User.where.not(avatar_id: nil).find_each do |user|
      tmp_file = Tempfile.new

      # Read S3 object to our tmp_file
      s3_client.get_object(
        response_target: tmp_file.path,
        bucket: ENV['AWS_S3_BUCKET'],
        key: "store/#{user.avatar_id}"
      )

      # Find content_type of S3 file using ImageMagick
      # If you've been smart enough to save :avatar_content_type with Refile, you can use this value instead
      content_type = MiniMagick::Image.new(tmp_file.path).mime_type

      # Attach tmp file to our User as an ActiveStorage attachment
      user.avatar.attach(
        io: tmp_file,
        filename: "avatar.#{content_type.split('/').last}",
        content_type: content_type
      )

      if user.avatar.attached?
        user.save # Save our changes to the user
        puts "- migrated #{user.try(:name)}'s avatar image."
      else
        puts "- \e[31mFailed to migrate the avatar image for user ##{user.id} with Refile id #{user.avatar_id}\e[0m"
      end

      tmp_file.close
    end

    # Now remove the actual Refile column
    remove_column :users, :avatar_id, :string
    # If you've created other Refile fields like *_content_type, you can safely remove those as well
    # remove_column :users, :avatar_content_type, :string
  end

  def down
    raise ActiveRecord::IrreversibleMigration
  end
end