通过JSON API上传图像时出现TypeError

时间:2014-08-02 21:09:17

标签: ruby-on-rails json ruby-on-rails-4 amazon-s3 carrierwave

我使用Carrierwave将图像直接上传到Amazon S3。我有一个用于上传的JSON API,我在客户端将图像编码为Base64并发送它。 我按照this教程博客文章进行了操作。

图片上传在控制台上显示此消息失败:

INSERT INTO "photos" ("created_at", "description", "image", "place_id", "review_id", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?, ?)  [["created_at", Sat, 02 Aug 2014 13:43:24 PDT -07:00], ["description", "rainbow"], ["image", #<ActionDispatch::Http::UploadedFile:0x007fb86caf8b98 @tempfile=#<Tempfile:/var/folders/3n/qvctcdv17cn2kp4083pt4f6c0000gn/T/uploaded-photo20140802-7745-1g7ic67>, @original_filename="image.JPG", @content_type=nil, @headers=nil>], ["place_id", 1], ["review_id", 1], ["updated_at", Sat, 02 Aug 2014 13:43:24 PDT -07:00], ["user_id", 1]]
TypeError: can't cast ActionDispatch::Http::UploadedFile to string: INSERT INTO "photos" ("created_at", "description", "image", "place_id", "review_id", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?, ?)

我看到它试图插入到image列的数据库中的值不是对象的字符串。当我通过浏览器上传(不使用API​​)时,image列中插入的值只是文件名。

我在哪里错了?

这是我的控制器:

module Api
    module V1
        class PhotosController < ApplicationController

            def index
                if params[:place_id]
                    place = Place.find(params[:place_id])
                    @photos = place.photos
                end
            end

            def create
                user = User.where(:authentication_token => params[:auth_token])

                place = Place.find(params[:place_id])
                @photo = place.photos.build(photo_params)
                @photo.user_id = user.first.id

                @photo[:image] = parse_image_data(@photo_params[:image]) if @photo_params[:image]
                if @photo.save
                    @photo
                else
                    render json: { success: false, error: @photo.errors }
                end

            ensure
                clean_tempfile
            end

            def photo_params 
                @photo_params ||= params.require(:photo).permit(:description, :review_id, image:[:content_type, :filename, :file_data])
            end

            private

            def parse_image_data(image_data)
                @tempfile = Tempfile.new('uploaded-photo')
                @tempfile.binmode
                @tempfile.write Base64.decode64(image_data[:file_data])
                @tempfile.rewind

                ActionDispatch::Http::UploadedFile.new(
                    :tempfile => @tempfile,
                    :content_type => image_data[:content_type],
                    :filename => image_data[:filename]
                )
            end

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


        end
    end
end

这是我的模特。我在Image上安装了ImageUploader:

class Photo < ActiveRecord::Base
    validates :image, :presence => true
    belongs_to :place

    mount_uploader :image, ImageUploader    

end

我发送的JSON是:

{
    "auth_token": "9ycXsJ2rcWT-gy4gdLSN",
    "email": "myemail@gmail.com",
    "photo": {
        "image": {
            "content_type": "image/jpeg",
            "filename": "image.JPG",
            "file_data": "base64_data",
            "description": "a description"
        }
    }
}

以上JSON是从手工制作的测试脚本发送的:

require 'base64'
require 'net/http'
require 'json'

encoded_string = Base64.encode64(File.open("image.JPG", "rb").read)

@host = 'localhost'
@port = '3000'

@post_ws = "/api/places/1/photos/upload"

@image = { :content_type => "image/jpeg", :filename =>  "image.JPG", :file_data => encoded_string }

@payload = {"auth_token" => "9ycXsJ2rcWT-gy4gdLSN", "email" => "useremail@gmail.com", "photo" => {"image" => @image  , "description" => "rainbow", "review_id" => 1 }}.to_json

def post
     req = Net::HTTP::Post.new(@post_ws, initheader = {'Content-Type' =>'application/json'})
          req.body = @payload
          response = Net::HTTP.new(@host, @port).start {|http| http.request(req) }
           puts "Response #{response.code} #{response.message}:
          #{response.body}"
end


post()

1 个答案:

答案 0 :(得分:0)

我终于通过API上传照片了。 在create()函数中,而不是

@photo[:image] = parse_image_data(@photo_params[:image]) if @photo_params[:image]

我把它改成了

photo_params[:image] = parse_image_data(photo_params[:image]) if photo_params[:image]

以下是完整的代码:

    def upload
        user = User.where(:authentication_token => params[:auth_token])

        place = Place.find(params[:place_id])

        photo_params[:image] = parse_image_data(photo_params[:image]) if photo_params[:image]

        @photo = place.photos.build(photo_params)
        @photo.user_id = user.first.id

        if @photo.save
            @photo
        else
            render json: { success: false, error: @photo.errors }
        end

    ensure
        clean_tempfile
    end

    def photo_params 
        @photo_params ||= params.require(:photo).permit(:description, :review_id, image:[:content_type, :filename, :file_data])
    end

    private

    def parse_image_data(image_data)
        @tempfile = Tempfile.new('uploaded-photo')
        @tempfile.binmode
        @tempfile.write Base64.decode64(image_data[:file_data])
        @tempfile.rewind

        ActionDispatch::Http::UploadedFile.new(
            :tempfile => @tempfile,
            :content_type => image_data[:content_type],
            :filename => image_data[:filename],
            :original_filename => image_data[:original_filename]
        )
    end

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