我使用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()
答案 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