Using respond_to ... format.json and jQuery Form Plugin by malsup

Topher Fangio picture Topher Fangio · Feb 9, 2010 · Viewed 12.2k times · Source

I'm having a tad bit of trouble getting the jQuery Form Plugin to work properly with a file-upload field. When I use the plugin to submit the form without a file-upload field, the format.json portion of the respond_to do |format| block is called properly. However, by adding the file-upload field, it only executes the format.html portion which makes my javascript code think that an error has occurred.

Has anyone run into this before or know a way to force the plugin to always use json? Alternatively, can I modify the url that the plugin uses to force Rails to render the json?

Thanks very much for any help! Code below:

# app/controllers/details_controller.rb
def create
  @detail = Detail.new(params[:detail])

  style = params[:detail_style].to_sym || :thumb
  data = { :id => '5', :url => 'test.rails' }

  respond_to do |format|
    if @detail.save
      flash[:notice] = 'Your image has been saved.'
      data = { :id => @detail.id, :url => @detail.data.url(style) }

      format.html { redirect_to :action => 'index' }
      format.json { render :json => "<textarea>#{data.to_json}</textarea>", :status => :created }
    else
      format.html { render :action => 'new' }
      format.json { render :json => @detail.errors, :status => :unprocessable_entity }
    end
  end
end

/* app/views/sidebar/_details.html.erb (excerpt) */

<% form_for(Detail.new, :html => { :multipart => true } ) do |f| %>
  <%= hidden_field_tag 'detail_style', 'thumb' %>

  <%= f.label :image, "Recent Images" %>
  <%= f.file_field :image%>

  <p> 
    <%= f.submit "Upload" %>
  </p>
<% end %>

<script>
$(document).ready(function() {
  var options = {
    dataType: 'json',

    success: function(json, statusText) {
      console.log("success: " + json);
    },

    error: function(xhr, statusText, errorThrown) {
      console.log("error: " + xhr.responseText);
    }
  };

  $('#new_detail').ajaxForm(options);
});

Answer

TsenYing picture TsenYing · Sep 17, 2010

Several things are needed to make jQuery Form plugin work for file uploads with a JSON response. In the javascript, the options for .ajaxForm should have:

dataType: 'json', // evaluate return as JSON

The browser needs to tell the Rails action to return content as JSON, one way to do this is add a hidden format input field in the file upload form template:

<%= hidden_field_tag 'format', 'json' %>

The Rails action will then run the format.json method inside the respond_to block.

In the server action

  • encapsulate JSON in a tag, .ajaxForm will unwrap the string and eval JSON correctly
  • set return content type to “text/html”, otherwise some browsers (Firefox) will try to download the return into a file.

e.g.

  respond_to do |format|
    format.json {
          render :json => "<textarea>#{data.to_json}</textarea>", :content_type => "text/html"
    }
  }