在Rails中通过POST上传CSV

时间:2016-05-26 04:12:29

标签: ruby-on-rails csv

我正在尝试将一个csv文件上传到Rails并将其解析为db。我尝试使用Paw和Postman发送http请求,指定POST,附加csv文件,并将Content-Type指定为application / csv

请求标头:

POST /skate_parks/import HTTP/1.1
Content-Type: text/csv
Host: localhost:3000
Connection: close
User-Agent: Paw/2.3.4 (Macintosh; OS X/10.11.5) GCDHTTPRequest
Content-Length: 11663

Name,Address,Suburb,Postcode,State,Business Category,LGA,Region,
Aireys Inlet Skate Park,Great Ocean Road,Aireys Inlet,3231,VIC,Skate Parks,Surf Coast,Barwon S/W, etc...

控制器skate_parks_controller.rb

def import
  SkatePark.import(params[:body])
end

模型

class SkatePark < ApplicationRecord

  require 'csv'

  def self.import(file)
    CSV.foreach("file", headers: true) do |row|

      skate_park_hash = row.to_hash
      skate_park = SkatePark.where(name: skate_park_hash["name"])

      if skate_park.count == 1
        skate_park.first.update_attributes(skate_park_hash)
      else
        SkatePark.create!(skate_park_hash)
      end
    end
  end
end

错误

Started POST "/skate_parks/import" for ::1 at 2016-05-26 13:48:34 +1000
Processing by SkateParksController#import as HTML
Completed 500 Internal Server Error in 3ms (ActiveRecord: 0.0ms)
Errno::ENOENT (No such file or directory @ rb_sysopen - file):
app/models/skate_park.rb:6:in `import'
app/controllers/skate_parks_controller.rb:7:in `import'

1 个答案:

答案 0 :(得分:2)

问题是params[:body]nil,因此您实际上是在调用SkatePark.import(nil)。 Rails没有将原始POST主体放入params,就像你显然认为的那样。

您有两种选择。在我看来,更好的选择是将数据上传为multipart/form-data。当用户在<input type="file">中选择文件时,您将执行与浏览器相同的操作,而不是将原始数据放入POST主体,也就是说您将其编码为表单数据。执行此操作后,您能够通过params访问数据,如“上传文件”下的Form Helpers Rails Guide中所述。 (由于您显然没有使用表单,因此可以跳到“上传的内容”以了解如何处理您收到的数据。)

要使用Postman对此进行测试,请按照Sending Requests文档中“请求正文”下的“表单数据”说明进行操作,我将在此处摘录以供后人使用:

  

multipart / form-data是Web表单用于传输数据的默认编码。这模拟在网站上填写表格并提交。表单数据编辑器允许您为数据设置键/值对(使用key-value editor)。您也可以将文件附加到密钥。

您的另一个选择是直接通过request.raw_post访问POST正文,如下所述:How to access the raw unaltered http POST data in Rails?这不是非常“Railsy”,但是,其他事情将更难以测试。