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):
- Setup upload_progress and respond_to_parent plugins
- 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:
- Find your form footer (should be
<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.





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
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/
Hello I installed the plugins and now? I need generate any model?
8vvv2j34bdms 5jwgszrqvs2anecdy 8lfhpn6lddr2zn1l