簡體   English   中英

未定義的方法'execute_prepared'將Rails回形針遷移到ActiveStorage

[英]undefined method `execute_prepared' Rails Paperclip to ActiveStorage migration

我正在嘗試將Rails應用程序從使用Paperclip轉換為ActiveStorage,並且遇到遷移指南中提供的ConvertToActiveStorage遷移腳本的問題。 https://github.com/thoughtbot/paperclip/blob/master/MIGRATING.md#copy-the-database-data-over

以下是我嘗試運行Paperclip到ActiveStorage遷移時遇到的錯誤。 我不確定ActiveRecord::Base.connection.execute_prepared是什么問題

Paperclip當前保存用戶上載文件的路徑為/web/non-public/system/articles/documents/000/000/ 000/000 /web/non-public/system/articles/documents/000/000/並且ActiveStorage應該在遷移后將其保存到/web/storage的新位置。

    == 20190123165105 ConvertToActiveStorage: migrating ===========================
    -- transaction()
    rails aborted!
    StandardError: An error has occurred, this and all later migrations canceled:

    undefined method `execute_prepared' for #<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter:0x007fd7e9211128>
    Did you mean?  exec_delete
    /web/db/migrate/20190123165105_convert_to_active_storage.rb:45:in `block (4 levels) in up'
    /web/db/migrate/20190123165105_convert_to_active_storage.rb:40:in `each'
    /web/db/migrate/20190123165105_convert_to_active_storage.rb:40:in `block (3 levels) in up'
    /web/db/migrate/20190123165105_convert_to_active_storage.rb:39:in `each'
    /web/db/migrate/20190123165105_convert_to_active_storage.rb:39:in `block (2 levels) in up'
    /web/db/migrate/20190123165105_convert_to_active_storage.rb:28:in `each'
    /web/db/migrate/20190123165105_convert_to_active_storage.rb:28:in `block in up'
    /web/db/migrate/20190123165105_convert_to_active_storage.rb:27:in `up'
    bin/rails:4:in `require'
    bin/rails:4:in `<main>'

    Caused by:
    NoMethodError: undefined method `execute_prepared' for #<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter:0x007fd7e9211128>
    Did you mean?  exec_delete

指南中提供的遷移腳本在此處列出。

class ConvertToActiveStorage < ActiveRecord::Migration[5.2]
  require 'open-uri'

  def up
    # postgres
    get_blob_id = 'LASTVAL()'
    # mariadb
    # get_blob_id = 'LAST_INSERT_ID()'
    # sqlite
    # get_blob_id = 'LAST_INSERT_ROWID()'

    active_storage_blob_statement = ActiveRecord::Base.connection.raw_connection.prepare('active_storage_blob_statement', <<-SQL)
      INSERT INTO active_storage_blobs (
        key, filename, content_type, metadata, byte_size, checksum, created_at
      ) VALUES ($1, $2, $3, '{}', $4, $5, $6)
    SQL

    active_storage_attachment_statement = ActiveRecord::Base.connection.raw_connection.prepare('active_storage_attachment_statement', <<-SQL)
      INSERT INTO active_storage_attachments (
        name, record_type, record_id, blob_id, created_at
      ) VALUES ($1, $2, $3, #{get_blob_id}, $4)
    SQL

    Rails.application.eager_load!
    models = ActiveRecord::Base.descendants.reject(&:abstract_class?)

    transaction do
      models.each do |model|
        attachments = model.column_names.map do |c|
          if c =~ /(.+)_file_name$/
            $1
          end
        end.compact

        if attachments.blank?
          next
        end

        model.find_each.each do |instance|
          attachments.each do |attachment|
            if instance.send(attachment).path.blank?
              next
            end

            ActiveRecord::Base.connection.execute_prepared(
              'active_storage_blob_statement', [
                key(instance, attachment),
                instance.send("#{attachment}_file_name"),
                instance.send("#{attachment}_content_type"),
                instance.send("#{attachment}_file_size"),
                checksum(instance.send(attachment)),
                instance.updated_at.iso8601
              ])

            ActiveRecord::Base.connection.execute_prepared(
              'active_storage_attachment_statement', [
                attachment,
                model.name,
                instance.id,
                instance.updated_at.iso8601,
              ])
          end
        end
      end
    end
  end

  def down
    raise ActiveRecord::IrreversibleMigration
  end

  private

  def key(instance, attachment)
    SecureRandom.uuid
    # Alternatively:
    # instance.send("#{attachment}_file_name")

    # filename = instance.send("#{attachment}_file_name")
    # klass = instance.class.table_name
    # id = instance.id
    # id_partition = ("%09d".freeze % id).scan(/\d{3}/).join("/".freeze)
    # "#{klass}/#{attachment.pluralize}/#{id_partition}/original/#{filename}"    
  end

  def checksum(attachment)
    # local files stored on disk:
    url = attachment.path
    Digest::MD5.base64digest(File.read(url))

    # remote files stored on another person's computer:
    # url = attachment.url
    # Digest::MD5.base64digest(Net::HTTP.get(URI(url)))
  end
end

運行遷移時,我遇到了同樣的問題。 我不得不更改兩個execute_prepared語句以改為使用exec_prepared

ActiveRecord::Base.connection.raw_connection.exec_prepared(
    'active_storage_blob_statement', [
        ...
])

ActiveRecord::Base.connection.raw_connection.exec_prepared(
    'active_storage_attachment_statement', [
        ...
])

我不太清楚為什么,但是我還必須將插入的最后一個Blob記錄的ID傳遞給附件insert語句。 如果不需要,可以跳過此步驟:

active_storage_attachment_statement = ActiveRecord::Base.connection.raw_connection.prepare('active_storage_attachment_statement', <<-SQL)
  INSERT INTO active_storage_attachments (
    name, record_type, record_id, blob_id, created_at
  ) VALUES ($1, $2, $3, #{"(SELECT max(id) from active_storage_blobs)"}, $4)
SQL

這是我完成的遷移

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM