RubyOnRails: AJAX File Upload Hint 4

Posted by yrashk

If you have an Ajax form (like in Ajaxscaffold) and you want to attach 1+ files to object you edit, you can follow my path (I don’t guarantee it is a shortest path):

  • Define your upload_status action:
 
    def upload_status
        render :nothing
    end
 
  • Outside of your AJAX form (in the case of Ajaxscaffold, after closing form tag in _new_edit.rhtml), setup an upload form in a partial (in _binary_file.rhtml)
 
  <%= render :partial => 'binary_file', :locals => { :obj => @obj } %>
 
  • _binary_file.rhtml:
 
  <div id="upload-box">
    <%= form_tag_with_upload_progress({ :action => 'upload_file' }) %>
                  <%= hidden_field 'obj_id', obj.id %>
        Select file to upload: <%= file_field_tag 'obj_file' %>
        <%= submit_tag "Upload" %>
    </form>
  </div>
 
  • In your controller, define upload_file action:
 
    def upload_file
        bf = BinaryFile.create :uploaded_file => params[:obj_file]
        @obj = Obj.find(params[:obj_id])
        responds_to_parent do
            render :update do |page|
                page.replace_html "upload-box", 
                                              :partial => "binary_file",
                                             :locals => { :obj => @obj,  
                                                          :binary_file => bf }
            end
      end
    end
 
  • In _form.rhtml (form file for Ajaxscaffold or wherever your form content is available):
 
   <%= hidden_field 'obj', 'datafile_id' %>
 
  • In _binary_file.rhtml:
 
       <% if obj.datafile %>
    <%= javascript_tag "$('obj_datafile_id').value=#{obj.datafile.id};" %>
    <%= link_to "File",
        { :controller => "binary_files", :action => "show", :id => ob.datafile.id }, 
        { :target => "_blank" } %>
       <% else %>
    <%= javascript_tag "$('obj_datafile_id').value=#{binary_file.id};" %>
    <%= link_to "File",
        { :controller => "binary_files", :action => "show", :id => binary_file.id }, 
        { :target => "_blank" } %>
      <% end %> 

  • Right now you have your binary files after Update and Cancel actions, which looks bad. You might want to use the following trick:
    • Find your form footer (should be
      <p class="form-footer">
      for Ajaxscaffold) and kill it or set display: none in its style.
    • Then, create your own form footer after rendering binary_file partial(s). Here you are an Ajaxscaffold example:
 
     <p class="form-footer">
          <%= submit_to_remote Inflector.titleize(@options[:action]), "Update",
        :url => @options.merge(:controller => @scaffold_controller),
                    :loading => "Element.show('#{loading_indicator_id(@options)}'); Form.disable('#{element_form_id(@options)}');",
                    :html => { :href => url_for(@options.merge(:controller => @scaffold_controller)),
                               :id => element_form_id(@options)+'submission_helper' },
                    :submit => element_form_id(@options) %>
          <% cancel_params = @options.merge(:controller => @scaffold_controller, :action => 'cancel'+@suffix, :referring_action => @options[:action]) %>
          <%= link_to_remote "Cancel",
            { :url => cancel_params,
            :confirm => "Your changes will be lost. Continue?",
              :loading => "Element.show('#{loading_indicator_id(@options)}');" },
          { :href => url_for(cancel_params) } %>
          <%= loading_indicator_tag @options %>
        </p>
 

That’s all, folks!

P.S. I haven’t re-checked this extraction yet. Please comment if you will find something missing or unobvious. Thank you.

P.P.S. I know that it could be refactored to make all this stuff nicer. I’ll do that when I will have another free minute.

P.P.P.S. I have removed actual upload progress consciously in my example. However, it shouldn’t be a big problem to enable it again.

Comments

Leave a response

  1. SuhasFebruary 05, 2007 @ 02:24 AM

    Hi,

    Its nice tutorial but could you please help regarding to setup upload_progress and respond_to_parent plugins.

    I am confused.

    — Thanks, Suhas, nehete.suhas@gmail.com

  2. VichoFebruary 13, 2007 @ 07:49 AM

    I don’t know if it’s correct…

    In your rails application directory, using the console write:

    ruby script/plugin install http://dev.rubyonrails.org/svn/plugins/upload_progress/ ruby script/plugin install http://sean.treadway.info/svn/plugins/responds_to_parent/

  3. PedroApril 08, 2007 @ 10:17 AM

    Hello I installed the plugins and now? I need generate any model?

  4. xsk8i3c942June 02, 2007 @ 11:38 AM

    8vvv2j34bdms 5jwgszrqvs2anecdy 8lfhpn6lddr2zn1l

Comment