I am trying to create a form that takes values from a table of input boxes. The user can enter the values in this table manually, or upload an excel spreadsheet. All of this works fine, but I want the user to be able to import a spreadsheet, and have the data table updated without reloading the page. The primary model to store this information is a DataTable object.
views/data_tables/index.html.erb looks like this:
<div id="tabs" class="tabs-bottom">
<ul>
<li><a href="#tabs-1">Data Input</a></li>
<li><a href="#tabs-2">Data Display</a></li>
</ul>
<div class="tabs-spacer"></div>
<div id="tabs-1" class="tab_frame">
<%= render @data_table %>
</div>
<div id="tabs-2" class="tab_frame">
<%= render "data_display" %>
</div>
</div>
I am using a tabbed view from the Jquery-UI.
The partial, views/data_tables/_data_table.html.erb, looks something like this:
<%= nested_form_for @data_table, :remote => true do |f| %>
<div id="table_pane">
<table id="table_input" class="table_input">
<tbody>
<%= f.fields_for :financial_rows, :wrapper => false do |dr| %>
<tr class="fields">
<td>
<%= dr.link_to_remove "x", {:class => "btn btn-danger"} %>
</td>
<td class="month">
<%= dr.text_field :month, :value => (dr.object.month.to_i) %>
</td>
<td class="year">
<%= dr.text_field :year, :value => (dr.object.year.to_i) %>
</td>
<td class="currency">
<% # . . . %>
<% #Multiple fields omitted for brevity %>
<% # . . . %>
</td>
</tr>
<% end %>
</tbody>
</table>
<%= f.link_to_add "+", :financial_rows, :data => { :target => "#table_input" }, :class => "btn btn-success" %></br>
</div>
<%= f.submit :value => "Render Data" %>
<% end %>
<%= form_tag import_data_tables_path, multipart: true, remote: true do %>
<%= file_field_tag :file %>
<%= submit_tag "Import Spreadsheet" %>
<% end %>
The import form at the end is what I am having trouble with. In my controller, controllers/data_tables_controller.rb, my import method looks like this:
def import
@data_table = DataTable.new
if !params[:file].blank?
imported_file = params[:file]
spreadsheet = read_file(imported_file)
header = spreadsheet.row(2)
(3..spreadsheet.last_row).each do |i|
data = Hash[[header, spreadsheet.row(i)].transpose]
f_row = FinancialRow.new
f_row.attributes = data.to_hash.slice(*FinancialRow.accessible_attributes)
@data_table.financial_rows << f_row
end
respond_to do |format|
format.html { redirect_to @data_table}
format.js
format.json { render json: @data_table, location: @data_table}
end
#render('index')
else
flash[:error] = "Select a file for import"
@data_table.financial_rows.build
#render('index')
end
end
When I import a file without trying to use Ajax, the page reloads with the text fields of the data table fully populated, but when I try to use Ajax, the page just reloads without any updates to the data table. I have written a javascript file which theoretically should replace the div the datatable is in.
views/data_tables/import.js.erb contains:
$("#tabs-1").html("<%= escape_javascript(render(:partial => @data_table)).html_safe %>");
I've scoured stackoverflow for hours, reading posts on how to replace a rendered partial using Ajax, but I haven't found anything that has worked for me. I'm sure it is something simple I am overlooking, but I'm having a lot of trouble wrapping my head around how Ajax is implemented with Rails, and how and why one should use either format.html, format.js, or format.json.
I am using rails 3.2.12. Some noteworthy gems I am using is the 'nested_form' gem to handle the data_table form, and 'roo' to handle importing the spreadsheet.