¶ ↑
CsvImportThis is a Rails plugin.
It provides a controller method called each_csv_row
and an accompanying view helper called csv_fields
.
You can set the name of the file field param by passing it as the first argument to the csv_fields
helper (it is ‘csv_file’ by default):
<%= csv_fields :csv_file_upload %>
You may also specify the file field param as the first argument to the each_csv_row
method in the controller (it too is ‘csv_file’ by default):
each_csv_row(:csv_file_upload) do |row_hash| # … end
By default, when each_csv_row
is called, any exceptions raised in the block will be rescued. The rows that triggered the exceptions will then be displayed in a table as part of the output from csv_fields
.
You can turn off rescuing by passing false
as the second argument to each_csv_row
:
each_csv_row(:csv_file_upload, false) do |row_hash| # … end
each_csv_row
extracts the names of the fields from the CSV and applies them to each row in the CSV creating a hash of key / value pairs. The resulting hash for a row from the example below would look something like this:
{:first_name => 'Bob', :last_name => 'Smith'}
If the first row does not contain the field names, each_csv_row
names them from 0 to the length (- 1) of the first row:
{0 => 'Bob', 1 => 'Smith'}
¶ ↑
ExampleIn your controller:
class EmployeesController < ActionController::Base include CsvImport def import_employee_records each_csv_row do |row_hash| Employee.destroy_all if params[:destroy_all_first] Employee.create!(row_hash) end end end
In your view (don’t forget to set :multipart => true):
<h2>Import Employee Records</h2> <%- form_tag import_employees_path, {:multipart => true} do -%> <%= csv_fields %> <p> <%= check_box_tag :destroy_all_first %> <%= label :destroy_all_first, 'Destroy all existing employee records first.' %> </p> <%- end -%>
¶ ↑
Other View Helpers IncludedAll of these are called in csv_fields
. These exist for flexibility’s sake. Feel free to mix and match or even override csv_fields
in your own helper.
csv_file_label(name = 'csv_file', text = 'CSV file to use', options = {}) csv_file_tag(name = 'csv_file', options = {}) csv_field_names_label(name = 'csv_field_names_in_first_row', text = 'Field name labels are in the first row.', options = {}) csv_field_names_check_box_tag(name = 'csv_field_names_in_first_row', value = '1', checked = true, options = {}) csv_rows_imported_content(wrapping_tag = :div, html_options = {}) csv_bad_rows_table(header = 'Bad CSV rows', html_options = {})
¶ ↑
To-do¶ ↑
Allow for mapping of incoming field name labels to expected or preferred keys:each_csv_row(:non_useful_key_name => :key_expected, :other_key => :better_key) do |row_hash| # … end
Or even…
each_csv_row(0 => :first_name, 1 => :last_name, 2 => :email) do |row_hash| # … end
¶ ↑
Move the view helper methods to FormHelper, FormHelper::InstanceTag, and FormBuilderSpecifically FormBuilder so that things like this are made possible:
<%- form_for @company do |f| -%> <p> <%= f.label :name, 'Company Name' %><br /> <%= f.text_field :name %> </p> # yadda, yadda <p> <%= f.csv_file_label :employees_csv_file, 'Import Employees from a CSV' %><br /> <%= f.csv_file :employees_csv_file %> </p> <p><%= f.submit 'Save' %></p> <%- end -%>