ruby-on-rails - ActiveStorage - 无法找到或构建 blob:预期可附加,得到 #<ActionDispatch::Http::UploadedFile

标签 ruby-on-rails file-upload graphql rails-activestorage graphql-ruby

重现步骤

gem

gem 'graphql', '1.13.2'
gem 'apollo_upload_server', '2.1.0'

app/graphql/mutations/create_document.rb

module Mutations
  class CreateDocument < Mutations::BaseMutation
    description "Create a document"

    argument :doc, ApolloUploadServer::Upload, required: true, description: "The document to upload"

    field :document, Types::Objects::DocumentType, null: false
    field :code, Types::Enums::CodeEnum, null: false

    def resolve(doc:)
      authenticate_user
      document = context[:current_user].documents.build(doc: doc)
      if document.save
        {document: document, code: "SUCCESS"}
      else
        raise GraphQL::ExecutionError.new(document.errors.full_messages.join(", "), extensions: {code: "UNPROCESSABLE_ENTITY", errors: document.errors})
      end
    end
  end
end

查询 GraphQL 服务器

Processing by GraphqlController#execute as */*
17:34:47 web.1         |
17:34:47 web.1         | Variables:
17:34:47 web.1         |   {"doc"=>
17:34:47 web.1         |     #<ActionDispatch::Http::UploadedFile:0x0000ffff6c90ffd0
17:34:47 web.1         |      @content_type="image/jpeg",
17:34:47 web.1         |      @headers=
17:34:47 web.1         |       "Content-Disposition: form-data; name=\"0\"; filename=\"www.abcd.jpg\"\r\n" +
17:34:47 web.1         |       "Content-Type: image/jpeg\r\n",
17:34:47 web.1         |      @original_filename="www.YTS.MX.jpg",
17:34:47 web.1         |      @tempfile=#<File:/tmp/RackMultipart20220101-9-dn78ar.jpg>>}
17:34:47 web.1         |
17:34:47 web.1         | Query:
17:34:47 web.1         |   mutation createDocument($doc: Upload!){createDocument(input: {doc: $doc}){document{url}}}

app/models/document.rb

class Document < ApplicationRecord
  ## RELATIONSHIPS
  has_one_attached :doc
  belongs_to :documentable, polymorphic: true, optional: true
  belongs_to :user, optional: true

  ## VALIDATIONS
  validate :doc_presence, on: :create

  def doc_presence
    pattern = %r{^(image|application|text)/(.)+$}
    unless doc.attached? && pattern.match?(doc.attachment.blob.content_type)
      errors.add(:doc, I18n.t("errors.models.document.file_presence"))
    end
  end
end

postman 网址:POST http://localhost:3000/graphql 表单数据

"operations" = {"query":"mutation createDocument($doc: Upload!){createDocument(input: {doc: $doc}){document{url}}}", "variables": { "doc": null }}
"map" = { "0": ["variables.doc"]}
"0" = FILE_TO_BE_UPLOADED

spec/graphql/mutations/create_document_spec.rb

require 'rails_helper'

module Mutations
  RSpec.describe CreateDocument, type: :request do
    describe '.resolve' do
      let(:session) {FactoryBot.create(:session)}
      it 'create a document for the user' do
        session.user.confirm
        headers = sign_in_test_headers session
        params = FactoryBot.attributes_for(:document, :with_image, user_id: session.user_id)
        query = <<-GRAPHQL
        mutation ($input: CreateDocumentInput!) {
          createDocument(input: $input) {
            document {
              id
              url
            }
          }
        }
        GRAPHQL
        file = fixture_file_upload("spec/support/fixtures/image.png")
        variables = {input: {doc: ::ApolloUploadServer::Wrappers::UploadedFile.new(fixture_file_upload("spec/support/fixtures/image.png"))}}
        response = ApiSchema.execute(query, variables: variables, context: {current_user: session.user})
      end
    end
  end
end

预期行为

文件应该附上

实际行为

Could not find or build blob: expected attachable, got #<ActionDispatch::Http::UploadedFile:0x0000ffff6c90ffd0 @tempfile=#<Tempfile:/tmp/RackMultipart20220101-9-dn78ar.jpg>, @original_filename="www.abcd.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"0\"; filename=\"www.abcd.jpg\"\r\nContent-Type: image/jpeg\r\n">
ArgumentError:
       Could not find or build blob: expected attachable, got #<Rack::Test::UploadedFile:0x0000aaaafe8ba7a0 @original_filename="image.png", @tempfile=#<Tempfile:/tmp/image20220101-1-c5c4q4.png>, @content_type=nil>
     # /usr/local/bundle/gems/activestorage-7.0.0/lib/active_storage/attached/changes/create_one.rb:74:in `find_or_build_blob'
     # /usr/local/bundle/gems/activestorage-7.0.0/lib/active_storage/attached/changes/create_one.rb:20:in `blob'
     # /usr/local/bundle/gems/activestorage-7.0.0/lib/active_storage/attached/changes/create_one.rb:12:in `initialize'
     # /usr/local/bundle/gems/activestorage-7.0.0/lib/active_storage/attached/model.rb:65:in `new'
     # /usr/local/bundle/gems/activestorage-7.0.0/lib/active_storage/attached/model.rb:65:in `doc='
     # /usr/local/bundle/gems/enumerize-2.5.0/lib/enumerize/base.rb:53:in `initialize'
     # ./app/graphql/mutations/create_document.rb:13:in `resolve'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema/resolver.rb:107:in `public_send'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema/resolver.rb:107:in `block (3 levels) in resolve_with_support'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema.rb:118:in `after_lazy'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema/resolver.rb:95:in `block (2 levels) in resolve_with_support'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema.rb:118:in `after_lazy'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema/resolver.rb:86:in `block in resolve_with_support'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema.rb:118:in `after_lazy'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema/resolver.rb:75:in `resolve_with_support'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema/relay_classic_mutation.rb:64:in `resolve_with_support'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema/field.rb:812:in `public_send'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema/field.rb:812:in `block in public_send_field'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema/field.rb:848:in `with_extensions'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema/field.rb:794:in `public_send_field'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema/field.rb:708:in `block in resolve'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema.rb:118:in `after_lazy'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema/field.rb:706:in `resolve'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/execution/interpreter/runtime.rb:510:in `block (4 levels) in evaluate_selection_with_args'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/tracing.rb:66:in `trace'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/execution/interpreter/runtime.rb:509:in `block (3 levels) in evaluate_selection_with_args'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/query.rb:366:in `block in with_error_handling'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/execution/errors.rb:107:in `with_error_handling'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/query.rb:365:in `with_error_handling'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/execution/interpreter/runtime.rb:508:in `block (2 levels) in evaluate_selection_with_args'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/execution/interpreter/runtime.rb:796:in `resolve_with_directives'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/execution/interpreter/runtime.rb:505:in `block in evaluate_selection_with_args'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/execution/interpreter/runtime.rb:899:in `after_lazy'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/execution/interpreter/runtime.rb:439:in `evaluate_selection_with_args'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/execution/interpreter/runtime.rb:431:in `block in evaluate_selection'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/schema/member/has_arguments.rb:204:in `block (3 levels) in coerce_arguments'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/dataloader.rb:181:in `block in run'
     # /usr/local/bundle/gems/graphql-1.13.2/lib/graphql/dataloader.rb:303:in `block in spawn_fiber'

系统配置

Rails 版本:7.0.0

ruby 版本:3.0.3

最佳答案

首先您需要创建 blob 文件以用于事件存储。

def attach_doc(doc_param)
  doc = ActiveStorage::Blob.create_and_upload!(
    io: doc_param,
    filename: doc_param.original_filename,
    content_type: doc_param.content_type
  )
  document = context[:current_user].documents.doc.attach(doc)    
end
In rails < 7.0 method is ActiveStorage::Blob.create_after_upload

关于ruby-on-rails - ActiveStorage - 无法找到或构建 blob:预期可附加,得到 #<ActionDispatch::Http::UploadedFile,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70550808/

相关文章:

PHP:如何在表格的正确位置显示上传的文件名

javascript - 跨浏览器拖放 HTTP 文件上传?

javascript - GraphQL - 如何响应不同的状态码?

postgresql - 运行 mix ecto.setup 命令时连接被拒绝,使用 asdf 安装的软件包

ruby-on-rails - Ruby/Rails 3.1 : Given a URL string, 删除路径

ruby-on-rails - protected 方法 'update'调用了#<Project

javascript - 将文件从输入传输到 iframe JavaScript

javascript - Apollo 服务器: pass arguments to nested resolvers

javascript - 来自 Controller 的 Mixpanel.track

ruby-on-rails - Ruby 中的时间差异(以分钟为单位)