将文件发送到Rails JSON API

Emi*_*äck 29 json ruby-on-rails ruby-on-rails-3.2

我知道有类似的问题,但我还没有找到一个好的答案.我需要做的是将一个对象的描述发送到我的一个创建方法,其中包括一些不同的属性,包括一个名为:image,paperclip attachment:

has_attached_file :image
Run Code Online (Sandbox Code Playgroud)

现在我已经读过,通过将图像编码和解码为base64,可以直接在JSON中完成发送图像,但这对我来说感觉就像一个肮脏的解决方案.必须有更好的方法.

另一个解决方案是发送multipart/form-data请求,就像LEEjava在这里描述的那样.这个问题的一个问题是在Rails 3.2.2中没有正确解释请求参数,并且JSON.parse在尝试解析params时吐出错误,或者可能是错误解释某些东西的Rails.

入门POST "/api/v1/somemodel.json?token=ZoipX7yhcGfrWauoGyog"为127.0.0.1在2012-03-18十五时53分30秒+0200处理采用API :: V1 :: SomeController#创建为JSON参数:{" {\n
\"parentmodel \":{\n \"superparent_id \":1,\n
\"description \":\"享受花朵\",\n \"\":"=> {"\n
{\n\"someattribute \":1,\n
\"someotherattribute \":2,\n\"图像\":\ "image1的\" \n
} \n "=> {"\N}\N} "=> nil}},"token"=>"ZoipX7yhcGfrWauoGyog"}

抱歉,这很难读.JSON.parse(params [:parentmodel])在这里是不可能的,我不能JSON.parse(params),因为令牌属性,JSON.parse(params)抛出此错误:

TypeError(无法将ActiveSupport :: HashWithIndifferentAccess转换为String)

这让我相信我要么完全错误地接近这个问题,要么我只是在做某事.无论哪种方式,我们都可以确定我对某事感到错误.:)

有一个更好的方法吗?有人可以指点我任何指南/教程,或写一个答案描述我应该如何处理这个问题?

先感谢您

更新: 所以我现在实际上已经开始工作,但仅限于测试.我不完全确定这是如何工作的,但也许有人可以为我填补空白?这是测试代码的一部分(图像:fixture_file_upload(...)是重要的部分).

parts_of_the_object = { someattribute: 0, someotherattribute: 0, image: fixture_file_upload('/images/plot.jpg', 'image/jpg') }
Run Code Online (Sandbox Code Playgroud)

我的params []看起来像提交的普通HTML表单,这很奇怪(而且很棒):

Parameters: {"superparentid"=>"1", "plots"=>[{"someattribute"=>"0", "someotherattribute"=>"0", "image"=>#<ActionDispatch::Http::UploadedFile:0x007f812eab00e8 @original_filename="plot.jpg", @content_type="image/jpg", @headers="Content-Disposition: form-data; name=\"plots[][image]\"; filename=\"plot.jpg\"\r\nContent-Type: image/jpg\r\nContent-Length: 51818\r\n", @tempfile=#<File:/var/folders/45/rcdbb3p50bl2rgjzqp3f0grw0000gn/T/RackMultipart20120318-1242-1cn036o>>}], "token"=>"4L5LszuXQMY6rExfifio"}
Run Code Online (Sandbox Code Playgroud)

请求就像使用rspec一样发出请求:

post "/api/v1/mycontroller.json?token=#{@token}", thefull_object
Run Code Online (Sandbox Code Playgroud)

所以我已经完成了所有工作.我只是不知道它是如何工作的!我希望能够自己创建这样的响应,不仅仅是来自RSpec.:-)

Tom*_*omJ 40

昨天我实际上在这个问题上度过了一段可怕的时间来做一些非常相似的事情.事实上,我写了一个问题:Base64从Android/Java上传到RoR Carrierwave

它归结为在控制器中创建上传的图像对象,然后将其注入到参数中.

对于这个特定的例子,我们正在使用base64文件(我假设你有,因为JSON不支持嵌入文件)并将其保存为系统中的临时文件,然后我们创建了UploadedFile对象并最终将其重新注入到PARAMS.

我的json/params看起来像什么:

picture {:user_id => "1", :folder_id => 1, etc., :picture_path {:file => "base64 awesomeness", :original_filename => "my file name", :filename => "my file name"}}
Run Code Online (Sandbox Code Playgroud)

这是我的控制器现在的样子:

  # POST /pictures
  # POST /pictures.json
  def create

    #check if file is within picture_path
    if params[:picture][:picture_path]["file"]
         picture_path_params = params[:picture][:picture_path]
         #create a new tempfile named fileupload
         tempfile = Tempfile.new("fileupload")
         tempfile.binmode
         #get the file and decode it with base64 then write it to the tempfile
         tempfile.write(Base64.decode64(picture_path_params["file"]))

         #create a new uploaded file
         uploaded_file = ActionDispatch::Http::UploadedFile.new(:tempfile => tempfile, :filename => picture_path_params["filename"], :original_filename => picture_path_params["original_filename"]) 

         #replace picture_path with the new uploaded file
         params[:picture][:picture_path] =  uploaded_file

    end

    @picture = Picture.new(params[:picture])

    respond_to do |format|
      if @picture.save
        format.html { redirect_to @picture, notice: 'Picture was successfully created.' }
        format.json { render json: @picture, status: :created, location: @picture }
      else
        format.html { render action: "new" }
        format.json { render json: @picture.errors, status: :unprocessable_entity }
      end
    end
  end
Run Code Online (Sandbox Code Playgroud)

此时唯一要做的就是删除临时文件,我相信可以这样做 tempfile.delete

我希望这有助于你的问题!昨天我整天都在寻找解决方案,而我所看到的一切都是死路一条.但是,这适用于我的测试用例.


Sha*_*non 9

TomJ给出了一个很好的答案,但至少在Rails 3/Ruby 1.9中有一些小漏洞.

首先,不要尝试在params对象中调用可能是UploadedFile对象的[]..is_a?(Hash)例如,确保先检查它.

另外,请tempfile.rewind()在写完后确认,否则你将得到0长度的文件.

:original_filenameUploadedFile的构造函数的参数中的键是不必要/未使用的.另一方面,您可能想要提供:type密钥.找到类型值的简单方法是mime_type = Mime::Type.lookup_by_extension(File.extname(original_filename)[1..-1]).to_s

这是一个应用了更改的版本:

# POST /pictures
# POST /pictures.json
def create

  #check if file is within picture_path
  if params[:picture][:picture_path].is_a?(Hash)
    picture_path_params = params[:picture][:picture_path]
    #create a new tempfile named fileupload
    tempfile = Tempfile.new("fileupload")
    tempfile.binmode
    #get the file and decode it with base64 then write it to the tempfile
    tempfile.write(Base64.decode64(picture_path_params["file"]))
    tempfile.rewind()

    mime_type = Mime::Type.lookup_by_extension(File.extname(original_filename)[1..-1]).to_s
    #create a new uploaded file
    uploaded_file = ActionDispatch::Http::UploadedFile.new(
      :tempfile => tempfile,
      :filename => picture_path_params["filename"],
      :type => mime_type) 

    #replace picture_path with the new uploaded file
    params[:picture][:picture_path] =  uploaded_file
  end

  @picture = Picture.new(params[:picture])
  respond_to do |format|
    if @picture.save
      format.html { redirect_to @picture, notice: 'Picture was successfully created.' }
      format.json { render json: @picture, status: :created, location: @picture }
    else
     format.html { render action: "new" }
     format.json { render json: @picture.errors, status: :unprocessable_entity }
   end
 end
Run Code Online (Sandbox Code Playgroud)

结束

  • 在初始化 `mime_type` 之前需要 `original_filename = picture_path_params["original_filename"]` (2认同)

pee*_*gla 5

如果您使用的是carrierwave,为此目的有一个很棒的宝石

https://github.com/lebedev-yury/carrierwave-base64