Rails - 如何在我的方法中访问 ActionDispatch UploadedFile 默认属性?

问题描述

我是 Rails 的新手,正在构建一个简单的银行对帐单转换器应用程序。用户选择银行名称上传对账单,点击“转换”,转换后的文件自动下载。

如何在控制器中访问 Rails ActionDispatch::::Http::UploadedFile 属性,尤其是 content_type 属性?我想在通过在我的验证方法中使用该属性传递文件以在模型中进一步处理之前检查正确的文件类型。

我尝试了 .content_type[:content_type],但没有成功,结果是 NoMethodError,即使该方法在控制器中明确定义为私有方法

这是我当前的应用程序设置:

  • 在网页中,表单将允许用户提交 :bank:statement 参数。

  • ConvertersController 中,参数使用私有 converter_params 方法进行保护,从而产生以下完整参数(在服务器日志中捕获):

Parameters: {"authenticity_token"=>"[FILTERED]","converter"=>{"bank"=>"bank1","statement"=>#<Actiondispatch::Http::UploadedFile:0x000055d9699140e0 @tempfile=#<Tempfile:/tmp/RackMultipart20210401-31472-dvsdde.pdf>,@original_filename="bank1.pdf",@content_type="application/pdf",@headers="Content-disposition: form-data; name=\"converter[statement]\"; filename=\"bank1.pdf\"\r\nContent-Type: application/pdf\r\n">},"commit"=>"convert"}

  • 然后在 :create 操作中,我将 file_check 私有方法应用于上传的语句(即 converter_params[:statement])以检查文件类型是否正确:
ConvertersController < ApplicationController
.
.
.
  def create
    @converter  = Converter.new(converter_params)

    if converter_params[:statement].nil?
      flash.Now[:alert] = "Error: no statement provided"
      render action: "index"
    elsif converter_params[:statement].file_check
      flash.Now[:alert] = "Error: wrong file type"
      render action: "index"
    else
      result      = @converter.run_conversion
      file_path   = Rails.root.join('public','output',result)

      stream_then_delete_statement(file_path)
    end
  end
.
.
.

  private 

  def converter_params
    params.require(:converter).permit(:bank,:statement)
  end

  def file_check
    pdf_statement = [ "bank1" ]
    csv_statement = [ "bank2" ]

    if pdf_statement.include? converter_params[:bank]
      self.content_type.pdf_check?
    elsif csv_statement.include? converter_params[:bank]
      self.content_type.csv_check?
    else
      exit(0)
    end
  end
.
.
.
end
  • 然后在模型中,csv_check? 私有方法引用了 pdf_check?file_check 方法
class MyModel < ActiveRecord::Base

  def pdf_check?
    self == "application/pdf"
  end

  def csv_check?
    self == "application/csv"
  end

.
.
.

end

然而,目前我得到了 NoMethodError,尽管 file_check 方法ConvertersController 中被明确定义为私有方法。这个错误让我感到困惑,因为 stream_then_delete_statement 等其他私有方法正常工作。

完全错误

NoMethodError in ConvertersController#create

undefined method `file_check' for #<Actiondispatch::Http::UploadedFile:0x000055d9699140e0 @tempfile=#<Tempfile:/tmp/RackMultipart20210401-31472-dvsdde.pdf>,@headers="Content-disposition: form-data; name=\"converter[statement]\"; filename=\"bank1.pdf\"\r\nContent-Type: application/pdf\r\n">

解决方法

您已在类 file_check 中定义了方法 ConvertersController,但使用类 ActionDispatch::Http::UploadedFile 的实例调用它。

您的错误消息说:

undefined method `file_check' for #<ActionDispatch::Http::UploadedFile:0x000055d9699140e0 @tempfile=#<Tempfile:/tmp/RackMultipart20210401-31472-dvsdde.pdf>,@original_filename="bank1.pdf",@content_type="application/pdf",@headers="Content-Disposition: form-data; name=\"converter[statement]\"; filename=\"bank1.pdf\"\r\nContent-Type: application/pdf\r\n">

这意味着它试图在类 ActionDispatch::Http::UploadedFile 的对象上调用方法 file_check 但找不到。

您应该直接调用该方法并将语句 params 作为参数传递给该方法:

elsif file_check(converter_params[:statement])
.
.
.
def file_check(statement_params)
.
.
.
end

您可以通过调用 self 找到当前对象。尝试使用像 byebug https://github.com/deivid-rodriguez/byebug 这样的调试器来检查它。