【问题标题】:undefined method `[]' for #<ActionDispatch::Http::UploadedFile#<ActionDispatch::Http::UploadedFile 的未定义方法“[]”
【发布时间】:2016-05-24 12:49:30
【问题描述】:

我对 Rails 很陌生,老实说,我对自己在做什么感到困惑,很抱歉在这里遗漏了任何基础知识...

这个related question 没有帮助

尝试通过 API 从 iOS 客户端应用程序将文件上传到我在 Heroku 上托管的 rails 应用程序。使用 form.file_field 上传时,已安装 Paperclip gem 和文件上传效果很好。但不是来自 API。

undefined method `[]' for #<ActionDispatch::Http::UploadedFile

在 /api/v1/foos/1 使用 PUT 方法上传文件时

型号

class Foo < ActiveRecord::Base

    has_attached_file :foo_file
    validates_attachment : foo_file, content_type: { content_type: ["application/xml"] }

end

控制器

class Api::V1::FoosController < Api::V1::BaseController

  def update

    result = { status: "failed" }

    begin
      params[:foo_file] = parse_foo_file_data(params[:foo_file]) if params[:foo_file]
      item = Foo.find(params[:id])
      item.foo_file = params[:foo_file]

      if item.save
        result[:status] = "success"
      end

    rescue Exception => e
      Rails.logger.error "#{e.message}"
    end

    ensure
      clean_tempfile

    foo = Foo.find(params[:id])

    authorize foo

    if !foo.update_attributes(update_params)
      return api_error(status: 422, errors: foo.errors)
    end

    render json: result.to_json

  end

  def parse_foo_file_data(foo_file_data)
    @tempfile = Tempfile.new('item_foo_file')
    @tempfile.binmode
    @tempfile.write Base64.decode64(foo_file_data.read)
    @tempfile.rewind

    uploaded_file = ActionDispatch::Http::UploadedFile.new(
      tempfile: @tempfile,
      original_filename: foo_file_data.original_filename
    )

    uploaded_file.content_type = foo_file_data.content_type
    uploaded_file
  end

  def clean_tempfile
    if @tempfile
      @tempfile.close
      @tempfile.unlink
    end
  end

  def update_params
   params.require(:app).permit(
     :name, :user_id, :foo_file
     )
  end
end

最终,我将不胜感激在上传此文件并将其附加到 foo 对象的 foo_file 参数方面的任何帮助。我认为这与我指出的未定义方法错误有关。或者我可能完全不在基地。感谢您的宝贵时间和帮助!

编辑:

新的服务器日志

Started PUT "/api/v1/foos/1

Processing by Foo::V1::FoosController#update as JSON

Parameters: 
{"foo"=>{"name"=>"newnameB"}, "foo_file"=>#<ActionDispatch::Http::UploadedFile:0x007fac81c82168 @tempfile=#<Tempfile:/tmp/RackMultipart20160523-6-q6pyac.xml>, @original_filename="Main.xml", @content_type="multipart/form-data", @headers="Content-Disposition: form-data; name=\"foo_file\"; filename=\"Main.xml\"\r\nContent-Type: multipart/form-data\r\n">, "id"=>"1"}

undefined method `gsub' for nil:NilClass

Completed 200 OK in 25ms (Views: 0.4ms | ActiveRecord: 3.6ms)

【问题讨论】:

  • 我认为你这里有一个空间破坏了它。 " :name, :user_id, : foo_file" 应该是 " :name, :user_id, :foo_file"
  • 抱歉,我只是将名称错误地翻译成“foo”。我的实际代码中没有空格。我已经编辑了帖子。感谢您对细节的关注。

标签: ruby-on-rails ruby heroku


【解决方案1】:

update 的开头附近,在这一行:

params[:foo_file] = parse_foo_file_data(params[:foo_file]) if params[:foo_file]

您致电pase_foo_file_data(params[:foo_file])。您可以查看日志,params[:foo_file] 是否为 ActionDispatch::Http::UploadedFile 对象。

在下面,parse_foo_file_data 的定义如下:

def parse_foo_file_data(foo_file_data)
    @tempfile = Tempfile.new('item_foo_file')
    @tempfile.binmode
    @tempfile.write Base64.decode64(foo_file_data[:data])
    @tempfile.rewind
    # ... etc

在第三行,你有foo_file_data[:data]。但是foo_file_data 是一个 ActionDispatch::Http::UploadedFile 对象,而that class doesn't provide a [] method

您最有可能尝试做的是从 UploadedFile 对象中获取数据,在这种情况下,您需要更多类似于 @tempfile.write Base64.decode64(foo_file_data.read) 的内容

当您尝试进一步向下调用foo_file_data[:content_type] 时,您会遇到类似的问题,这需要是foo_file_data.content_type

【讨论】:

  • 这实际上是一个很好的建议,它消除了我遇到的错误。但是文件仍然不会上传到 foo 对象,我得到一个“失败”的响应。但是现在日志中有一个不同的错误。有没有人看到代码还有其他问题?我应该接受这个答案然后再次发布问题吗?
  • 在您粘贴的代码中没有直接调用gsub,因此仅从提供的信息中无法判断发生了什么。您可能想要记录异常回溯而不是(或除了)消息,例如e.backtrace.
  • 我也刚刚注意到,但你真的 shouldn't ever rescue Exception,这将拯救诸如NoMemoryException或SystemStackError之类的东西。除非您有充分的理由,否则您应该拦截的最广泛的错误是 StandardError。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-14
  • 2015-05-22
相关资源
最近更新 更多