Reputation: 17803
I want to upload a file from an Android client to a Rails JSON API server.
I'm sending a Multipart/form request from the Android client which looks like that:
Content-Type: multipart/form-data; boundary=d99ArGa2SaAsrXaGL_AdkNlmGn2wuflo5
Host: 10.0.2.2:3000
Connection: Keep-Alive
User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)
--d99ArGa2SaAsrXaGL_AdkNlmGn2wuflo5
Content-Disposition: form-data; name="POSTDATA"
Content-Type: application/json; charset=UTF-8
Content-Transfer-Encoding: 8bit
{"tags":["test"],"location_id":1,"post":{"content":"test"}}
--d99ArGa2SaAsrXaGL_AdkNlmGn2wuflo5
Content-Disposition: form-data; name="IMAGEDATA"; filename="testimage.jpg"
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
<BINARY DATA?
--d99ArGa2SaAsrXaGL_AdkNlmGn2wuflo5--
in the rails controller i'm creating the new post with this code:
@parsed_json = JSON(params[:POSTDATA])
@post = @current_user.posts.new(@parsed_json["post"])
how do I make Paperclip save the attachment from the multipart form ?
I can do it with something like this:
if params.has_key?(:IMAGEDATA)
photo = params[:IMAGEDATA]
photo.rewind
@filename = "/tmp/tempfile"
File.open(@filename, "wb") do |file|
file.write(photo.read)
end
@post.photo = File.open(@filename)
end
but it doesn't look like the best solution, also, the filename that is being passed in ther multipart request is not used.
Upvotes: 13
Views: 18154
Reputation: 141
The pure json way to do this is to not pass content-type multipart-form and pass the file as a base64 encoded string in the json.
I figured this out thanks this post: http://www.rqna.net/qna/xyxun-paperclip-throws-nohandlererror-with-base64-photo.html
Here's an example of the json:
"{\"account\":{\"first_name\":\"John\",\"last_name\":\"Smith\",\"email\":\"[email protected]\",\"password\":\"testtest\",\"avatar\":{\"data\":\"INSERT BASE64 ENCODED STRING OF FILE HERE\",\"filename\":\"avatar.jpg\",\"content_type\":\"image/jpg\"}}}"
Then in the controller process the incoming avatar like this before saving the model.
def process_avatar
if params[:account] && params[:account][:avatar]
data = StringIO.new(Base64.decode64(params[:account][:avatar][:data]))
data.class.class_eval { attr_accessor :original_filename, :content_type }
data.original_filename = params[:account][:avatar][:filename]
data.content_type = params[:account][:avatar][:content_type]
params[:account][:avatar] = data
end
end
Upvotes: 12
Reputation: 714
So, I'm guessing your Post
model looks something like this:
class Post < ActiveRecord::Base
has_attached_file :photo, :styles => { ... }
...
end
So you should be able to do something as simple as this:
@post.photo = params[:IMAGEDATA] if params[:IMAGEDATA].present?
@post.save if @post.valid?
And it should save the photo.
If you need to do something more complicated, try re-arranging the form data into the data that the format Paperclip expects. And if you need to dig deeper, take a look inside Paperclip's Paperclip::Attachment
class.
Stack Overflow Cross-Reference
Upvotes: 4