其实想说的是如何通过JSON文件的方式来上传图片。
问题描述
如标题所述,需要通过接口将图片上传到ROR项目中,如何实现?
解答
先说一个简单的。
以一个model picture为例,看一下具体步骤:
model picture的信息:
Table name pictures
id :integer
file_name :string
image :string
这里,设置routes, 建model,建controller的过程省略,可参见:Rails:Web API接口实作。
分三步走:
-
编辑 Gemfile
gem 'carrierwave' gem 'mini_magick'
终端执行
bundle
,重启服务器。 新增uploader
执行:
rails g uploader PicImage
编辑
app/uploaders/pic_image_uploader.rb
class PicImageUploader < CarrierWave::Uploader::Base + include CarrierWave::MiniMagick ...... end
编辑
app/models/picture.rb
,把 carrierwave 的 Uploader 挂上去。class Picture < ApplicationRecord + mount_uploader :image, PicImageUploader ...... end
设定create
编辑app/controllers/api/v1/pictures_controller.rb
中,create部分:
# upload image through api
class Api::V1::PicturesController < ApiController
before_action :authenticate_user!, only: %i[create]
def create
@picture = Picture.new(picture_params)
if @picture.save
render json: { file_name: @picture.file_name, image: @picture.image }
else
render json: { message: 'failed', error: @picture.errors }, status: 400
end
end
.......
private
def picture_params
params.permit(:file_name, :image)
end
end
再来个复杂的。👇
如何通过JSON文件来上传?
在搜索解答的过程中,发现了另一种方式,假定你需要通过JSON文件的方式去上传图片,如何实现?
即接口调用是这样的:/api/v1/pictures.json
,由于JSON不支持嵌入式文件,所以会有些波折。
具体的实现方式是先将需要上传的图片file经base64编译后,调用接口创建一个实例, 然后在picture controller的create中,对传递过来的参数file_base64进行解析, 将解析后的文件写入temfile,并通过ActionDispatch::Http::UploadedFile
来新建一个uploader file,如此,一个image从encoding到decoding的过程结束,再使用Picture.new创建即可。
具体来说,前面的步骤都一样,只是create部分会有些不同。
先给picture新增一个字段,file_base64, 它是图片经base64编译后得到的字符串。
执行:
rails g migration add_file_base64_to_pictures file_base64:string
rake db:migrate
picture.json文件长这样:
picture {:file_base64 => "file_base64", :file_name => "file_name"}
编辑app/controllers/api/v1/pictures_controller.rb
中,create部分:
class Api::V1::PicturesController < ApiController
before_action :authenticate_user!, only: %i[create]
def create
if params[:picture][:file_base64]
# create a new tempfile named file
tempfile = Tempfile.new('file')
tempfile.binmode
# get the file ,decode it with base64, write it to the tempfile
tempfile.write(Base64.decode64(params[:picture][:file_base64]))
# create a new uploaded file
@uploaded_file = ActionDispatch::Http::UploadedFile.new(tempfile: tempfile, filename: params[:picture][:file_name])
@picture = Picture.new(params[:picture])
@picture.image = @uploaded_file
# delete the tempfile
tempfile.delete
end
if @picture.save
render json: @picture
else
render json: { message: 'failed', error: @picture.errors }, status: 400
end
end
end
这里,create部分显得很臃肿,我们skinny一下,改成这样:
class Api::V1::PicturesController < ApiController
before_action :authenticate_user!, only: %i[create]
before_action :process_file, only: %i[create]
def create
if @picture.save
render json: @picture
else
render json: { message: 'failed', error: @picture.errors }, status: 400
end
end
private
def process_file
if params[:picture][:file_base64]
tempfile = Tempfile.new('file')
tempfile.binmode
tempfile.write(Base64.decode64(params[:picture][:file_base64]))
@uploaded_file = ActionDispatch::Http::UploadedFile.new(tempfile: tempfile, filename: params[:picture][:file_name])
@picture = Picture.new(params[:picture])
@picture.image = @uploaded_file
tempfile.delete
end
end
end
呃,貌似process_file还是有点臃肿, 可以继续拆,这里就不实作了。
OK. 用postman测试一下,确认正常。
这里,你可能会问,编译后的文件在哪呢?在public/uploaders/picture/image下。
此外,上传的文件不需要 git commit, 在 .gitignore
中添加 public/uploads
这个目录即可。
参考
Sending files to a Rails JSON API