0

I have an application that allows users to submit stories via ajax, and then allows readers to comment on the stories with posts also submitted via ajax. I'm using Rails 3.0.3, ruby 1.9.2p290, and jquery 1.6.22. I'm also allowing users to include photos with their posts by using the rails paperclip 2.3 gem.

Everything works perfectly when the user does not include a photo with their posts. I get a response code of 200 from the server and the server responds with valid json that I can parse without a problem. My problem occurs when a user includes a photo.

When a user includes a photo then the I still get a server response code of 200, but for some reason the actual response from the server is in HTML rather than json (triggering a parsererror). What should be the json response is then included inside an HTML element. I can hack-up the html so to get the data that I need, but I'd rather do this right by having the server return valid json instead of json inside of HTML.

Here is the relevant code:

application.js:

jQuery.ajaxSetup({ 
  beforeSend: function(xhr) {
    xhr.setRequestHeader("Accept", "text/javascript")
  }
});

////show "please wait" icon when submitting a form via ajax or remotipart
$(document).delegate("form", "ajax:beforeSend ajax:remotipartSubmit", function(e, data, status, xhr){
  $("div.loading_new").attr('style', 'z-index: 9999');
});

//remove the "please wait" icon when the ajax request completes
$(document).delegate("form.new_post", "ajax:complete", function(e, data, status, xhr){
    $("div.loading_new_post").attr('style', '');
});

//immediately add a new post on successful ajax post request    
$(document).delegate("form.new_post", "ajax:success", function(e, data, status, xhr){
    pollingForNewPosts();  //immediately poll for new posts even if the polling timer hasn't tolled yet
    $("#bucket_for_new_post_form_story_"+data.post.story_id).slideUp(); 
    $("#bucket_for_new_post_form_story_"+data.post.story_id).empty();
});

Note, when I submit a post request without a photo both the success and the complete callbacks fire. When I submit a post with a photo, only the complete callback fires.

posts_controller.rb:

 def create
    @story = Story.find(params[:story_id])
    @post = @story.posts.build(params[:post])
    @post.user_id = current_user.id
    if @post.save 
      logger.debug "!!!!! #{@post.to_json}"
      render :json => @post
    end
 end

Here is the consol output for a post without an attachment followed by a post with an attachment. As you can see, both outputs reflect valid json without any html wrapper:

enter image description here

enter image description here

Here is a sample of the post form HTML:

<form id="new_post_for_story_55" class="new_post" novalidate="novalidate" method="post" enctype="multipart/form-data" data-remote="true" action="/stories/55/posts" accept_charset="UTF-8" target="">
  <div class="field">
    <label> Add to the story: </label>
    <br>
    <textarea id="new_post_contents_for_story_55" class="new_post_contents valid" name="post[contents]"></textarea>
    <div class="loading_new loading_new_post" style="">
      <img src="images/ajax-loader.gif">
    </div>
  </div>
  <div class="field">
    If you want to add a photo to your post, browse for it here:
     <input id="new_post_photo" class="valid" type="file" name="post[photo]">
  </div>
  <div class="actions">
    <input id="post_submit_story_55" class="submit_post button ui-button ui-widget ui-state-default ui-corner-all" type="submit" aria-disabled="false" role="button" value="Submit" name="commit">
    <input id="cancel_post_button_55" class="cancel_post button ui-button ui-widget ui-state-default ui-corner-all" type="button" aria-disabled="false" role="button" value="Cancel" name="cancel">
  </div>
</form>

And, here is the relevant parts of my post.rb file:

class Post < ActiveRecord::Base

  attr_accessor 
  attr_accessible :contents, :photo, :latitude, :longitude

  belongs_to    :story, :touch => true
  belongs_to    :user, :touch => true

  has_attached_file :photo, 
                    :styles => { :medium => "400x400>", :thumb => "100x100>" },
                    :storage => :s3,
                    :s3_credentials => "#{Rails.root.to_s}/config/s3.yml",
                    :path => "/:style/:id/:filename"

  validates   :contents,  :presence   => true,
                  :length     => {  :maximum => 299,
                                :minimum => 5 } 
  validates   :user_id,   :presence => true
  validates_attachment_content_type :photo, :content_type=>['image/jpeg', 'image/png', 'image/gif']

Finally, here is the response that I get from firebug with a post that does not include an attachment and then a very similar post with an attachment: enter image description here

As you can see, the second post the one with a photo attached via paperclip, and the response is in html. The first post doesn't have an attachment and its response is json.

I would be very thankful if you can help me figure out how to render responses in json to posts that include attachments with paperclip. I feel like I must be missing something very stupid, but try as I might, I just can't figure out my mistake.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
chuck w
  • 1,741
  • 2
  • 15
  • 34
  • You are logging @post.to_json, but rendering @post. Have you tried rendering @post.to_json instead or logging @post? Is there by chance a `app/views/posts/show.json.erb` file? – Nate Pinchot Feb 17 '12 at 20:03
  • Thanks for taking a look. Yep. I've tried rendering both `@post` and `@post.to_json`. Both yield the exact same results as the ones I've shown. Also, I don't have an app/views/posts/show.json.erb file. – chuck w Feb 17 '12 at 20:38
  • Hi I am having the same trouble, see http://stackoverflow.com/questions/12955288/trouble-with-paperclip-and-ajax-with-rails-3-2-8 – OfficeYA Virtual Offices Oct 18 '12 at 13:21

1 Answers1

0

Turns out that remotipart uses a hidden iframe to transport your image. As a result of edit action receiving an html request, your server returns an html response. Remotipart is smart enough to wrap your desired json response in html, and you can use $.parseJSON(data.responseText) to get at the json. But your browser, which is expecting a pure json response, will throw the parserror.

I believe that you can simply ignore this error.

chuck w
  • 1,741
  • 2
  • 15
  • 34