# config/application.rb
require 'csv'
# config/routes.rb
resources :products do
collection { post :import }
end
# products_controller.rb
def index
@products = Product.all
respond_to do |format|
format.html
format.csv { send_data @products.to_csv(['name', 'category', 'price']) }
end
end
def import
Product.import(params[:file])
redirect_to root_url, notice: "Products imported."
end
# product.rb
class Product < ApplicationRecord
def self.to_csv(fields = column_names, options = {})
CSV.generate(options) do |csv|
csv << fields
all.each do |product|
csv << product.attributes.values_at(*fields)
end
end
end
def self.import(file)
CSV.foreach(file.path, headers: true) do |row|
product_hash = row.to_hash
product = find_or_create_by!(name: product_hash['name'], category: product_hash['category'])
product.update_attributes(product_hash)
end
end
end
# index.html.erb
<%= form_tag import_products_path, multipart: true, class: 'form-inline' do %>
<div class="form-group">
<%= link_to "Export CSV", products_path(format: "csv"), class: 'btn btn-primary' %>
</div>
<div class="form-group">
<%= file_field_tag :file, class: '' %>
</div>
<div class="form-group">
<%= submit_tag "Import CSV", class: 'btn btn-info' %>
</div>
<% end %>
If you need to background process the file import, check out the ActiveJob branch of this episode's source