This project is archived and is in readonly mode.

#6392 new
Nick M

[patch] ActiveResource doesn't support file uploads/attachments

Reported by Nick M | February 9th, 2011 @ 05:26 AM

Problem

ActiveResource doesn't currently support file objects within an instance. If you try and save an ActiveResource instance that contains a file attachment, the file object's attributes get serialized, but not the file itself. For example, this is what ActiveResource currently sends when trying to create a new object that contains an uploaded file:

    <user>
      <first-name>Tom</first-name>
      <last-name>Jones</last-name>
      <address>1234 Test Rd</address>
      <avatar type="yaml">--- !ruby/object:ActionDispatch::Http::UploadedFile 
    content_type: image/png
    headers: |
      Content-Disposition: form-data; name="user[avatar]"; filename="Picture 4.png"
      Content-Type: image/png

    original_filename: Picture 4.png
    tempfile: !ruby/object:File {}
    </avatar>
    </user>

That serialized <avatar> content obviously won't work on the remote server since it doesn't actually contain the file data. You can try to base64 encode your file content inside the XML or JSON data being sent to the remote server, but that is cumbersome, slow, and requires individual changes to both your client and server code.

Patch

I've attached a patch with tests (for both master and the 3-0-stable branch) that gives you the option to send and encode your ActiveResource POST and PUT request data as application/x-www-form-urlencoded or, when file attachments are present, multipart/form-data. Since Net::HTTP doesn't natively handle mutlipart attachments, I introduced a dependency on the Payload class from rest-client.

To enable this new encoding option, I added a new class attribute, ActiveRecord::Base.payload_encoding. It works similar to how the format option works (it can be set globally or on a per-class basis). payload_encoding defaults to :serialized for compatibility (data will continue to be posted as serialized JSON or XML). Or payload_encoding can be set to :form to encode the attributes as form elements/multipart data for attachments.

This feature also seems handy to have for remote web services that expect data encoded this way (and not as JSON or XML).

Finally, regarding compatibility, it's disabled by default so it shouldn't interfere, but if you're targeting a Rails-based backend service, I believe enabling it should be mostly seamless. Since a Rails backend will automatically decode the XML and JSON data sent to into form parameters anyway, this simply negates the need for that step.

Example

    class Image < ActiveResource::Base
      self.site = "http://localhost:3001/"
      self.format = :json
      self.payload_encoding = :form
    end

Image.find and others will continue to fetch the data using JSON. However, Image.create and other save methods will post the data as form attributes, allowing multipart attachments to also work.

No comments found

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

People watching this ticket

Pages