如何将文件导入 Rails 系统上的 Ruby 而不会收到错误“没有文件或目录 sunch @ rb_sysopen - file.txt

How do I import a file to my Ruby on Rails system without receiving the error "No file or directory sunch @ rb_sysopen - file.txt

我的程序读取一个 .txt 文件,遍历内部信息并将其存储在数据库中。

但是发送文件时出现错误,说它不知道文件路径...据我了解,发送文件时它存储在作为源的变量中,但这没关系.

错误在附加图像中可见。请注意,一条尖线正是未找到的文件将被打开的位置。

但是说他没有找到文件很奇怪,如果在日志中他能够捕获文件并仍然传递文件名...这可能很重要。

控制器

def import

  errors = []
  file = params['file']
  File.open(file).each do |line|
  begin
    line = line.split("\t")

    next if line[0] == "Comprador"

    buyer = line[0] rescue row[0]
    description = line[1] rescue line[1] 
    unity_price = line[2].to_f rescue line[2].to_f
    quantiti = line[3].to_i rescue line[3] .to_i
    address = line[4] rescue line[4] 
    provider = line[5] rescue line[5] 
    total_gross = "Total: #{(unity_price * quantiti).round(2)}"

    Record.create(buyer: buyer, description: description, unity_price: unity_price,  quantiti: quantiti,  address: address,  provider: provider)
  rescue Exception => err
    errors << err.message
  end
end

if errors.banck?
  flash[:success] = "Imported with successful"
else
  flash[:error] = errors.join(", ")
end
redirect_to "/file"

查看

<%= form_tag import_path, method: :post do %>
 <div class="input-group no-border">
  <%= file_field_tag 'file' %>
  <%= button_tag 'submit'%>
 </div>
<% end %>

程序挂在行“File.open(文件).each do | line |”

我应该怎么做才能停止收到此错误消息?

当您在参数哈希中使用 file_field or file_field_tag in Rails you get an instance of ActionDispatch::Http::UploadedFile 时。这基本上只是一个临时文件实例的包装器。

你甚至不需要首先使用 File.open 并且它会导致错误,因为你在 UploadedFile 实例上隐式调用 #to_s 只是 returns 文件的基本名称。如果你想要路径,你会调用 #to_path 但同样 - 你不需要。

您可以通过调用 #open 打开一个 UploadedFile 实例 (duuh):

def import
  params[:file].open do |file|
    file.each do |line|
      # ...
    end
  end if params[:file]
end

但除此之外,这段代码确实是无法恢复的错误,并且充斥着诸如 errors.banck? 以及 anti-patterns 之类的内联救援(没有阻塞或异常的救援 class 救援 everything) 和 rescue Exception 这是 Pokémon exception handling 的主要例子。处理异常并不意味着埋葬一切。

从头开始,创建一个单独的服务对象,将文件作为输入并创建(和 returns)您的模型实例。编写覆盖它的测试。然后将其集成到您的控制器中。

这闻起来也很像你 reinventing the CSV wheel。你可以用这样的东西来做:

require 'csv'

# Parses the file as CSV and imports the rows into the database
# Usage `MyImporterService.call(file)`
class MyImporterService
  attr_accessor :status, :errors, :results

  def initialize(file)
    @file = file
    @results = []
    @errors = []
  end

  def call
    CSV.new(@file, { col_sep: "\t" }).each do |row|
      begin
        @results << Record.create!(row.slice(:buyer, :description, :unity_price, :quantiti,  :address, :provider))
      rescue ActiveRecord::RecordInvalid => e
        @errors << e.message
      end
    end
    @results
  ensure 
    @file.close
  end

  # convenience method
  def self.call(file)
    new(file).tap do |instance|
      instance.call
    end
  end

  private

  def status
    if @results.any? && @errors.none?
      :imported_without_errors
    elsif @results.any?
      :imported_with_errors
    elsif @results.none?
      :nothing_imported
    end
  end

  def success?
    status == :imported_without_errors
  end 
end
def import
  unless params[:file].present?
    render :something and return # bail early
  end
  @import = MyImporterService.call(file)
  if @import.success?
    redirect to: 'somewhere', success: 'Import went without a hitch'
  else
    render :something # give the user feedback
  end
end