Sunday, November 20, 2011

Allow ajax upload

Hello Rubies,
          Do you know how to upload the file through ajax? Last time i was juggling for ajax upload. There is some patch which i have used to allow ajax upload with rails 2.3.x. Follow below instruction to implement it.

Lets, consider the scenario. Where we have content page which has file(.pdf) upload and content area portion.

new.rhtml

<%= form_remote_tag(:url => {:controller => 'contents', :action => 'create'}, :html => { :multipart => true })%>     
    <p id='error_msgs'> </p>
    <p> Content: <%= text_area 'content', 'body' %> </p>
    <p> PDF: <%= file_column_field 'content', 'pdf_path' %> </p>
     <p> <%= submit_tag('Create') %> </p>
</form>
This form allow us to create content along with pdf upload through ajax.

Now want to add some basic validation for file?

class Content < ActiveRecord::Base
   validates_file_format_of :pdf_path , :in => ["pdf"]
   file_column(:pdf_path, :root_path => "#{RAILS_ROOT}/PDFs", :fix_file_extensions => nil)
end

Above we added the validation for file which must be in .pdf format only and store in our application's PDFs directory. You have to assume that your using file column here otherwise you can use normal file_field as well.

In controller of contents we have method called 'create' which need to enhance.

class ContentsController < ApplicationController
   
  def create
     @content = Content.new(params[:content])   
     responds_to_parent do
        if @content.save     
           render :update do |page|
              flash[:notice] = "content created successfully"
              page.redirect_to contents_url
           end
        else
           render :update do |page|
             page.replace_html "error_msgs", "#{error_messages_for :content}"
           end
        end
     end 
  end

end

Here you observed something ?.. we have used the responds_to_parent instead of respond_to block.

Now you guys are wondering about method 'responds_to_parent'. correct?
rails_responds_to_parent  is the method of gem 'rails_responds_to_parent t'. Now install that via
gem install rails_responds_to_parent

For the ajax support we have to add the patch called 'remote_upload' in lib folder of rails application

lib/remote_upload.rb

module ActionView
  module Helpers
    module PrototypeHelper
      alias_method :form_remote_tag_old, :form_remote_tag
      def form_remote_tag(options = {})
         if options[:html] && options[:html][:multipart]     
           uid = "a#{Time.now.to_f.hash}"                               
          <<-STR   
            <iframe name="#{uid}" id="#{uid}" src="about:blank" style="position:absolute;left:-100px;width:0px;height:0px;border:0px"></iframe>
            <form method="post" action="#{url_for options[:url].update({:iframe_remote => true})}" enctype="multipart/form-data" target="#{uid}" #{%(onsubmit="#{options[:loading]}") if options[:loading]}>
           STR
         else
            form_remote_tag_old(options)
         end
      end                            
    end
  end
end

This code will override the prototype's form_remote_tag method and allow iframe support.

Now, we have to include below lines in config/environment.rb to allow access of remote_upload and responds_to_parent

require 'remote_upload.rb'
require 'rails_responds_to_parent'

See our work completed. Now we will freely upload the file through ajax. Find interesting?
If you have any suggestion or query then post the comment.

to get the gem source of rails_responds_to_parent

3 comments:

  1. Hi,
    Thank you very much for this posting. It helped me a lot in my application.

    Regards,
    K. Subrahmanyam

    ReplyDelete
  2. Hey ,

    Your tutorial is a bit dated. I am using Rails 3 and running into an issue with uploading image file with AJAX form submission . I have the details of it on SO , here : http://stackoverflow.com/questions/16436443/rails-3-image-upload-form-submitting-with-http-instead-of-ajax

    Can you help me out with this ? I have been stuck since ever now .

    ReplyDelete
  3. This breaks when the form_remote_tag takes the block form such as:

    form_remote_tag :url => {...}, :html => {...} do |f|
    ...
    end

    Updating the patched "remote_upload.rb" file to accept the block and pass it through is good for the non-multipart case but I'm open to thoughts on how to incorporate it into the multipart "iframe" condition that patch accounts for.

    ReplyDelete