I was writing yesterday about how to write and test a CSV export in Rails 3.
Now let see the other side of the scope, where we would like to import a CSV file that will change our data structure.
Let says we have
Author
* email
* first_name
* last_name
* bio
We want to create a CSV updload that will update a couple email – first_name/last_name/bio.
Well, let’s write our acceptance test first
require 'acceptance/acceptance_helper'
feature "Uploading a CSV file" do
background do
@post = FactoryGirl.create(:author,
:email => "[email protected]",
:first_name => "nicholas",
:last_name => "Alpi",
:bio => "")
end
scenario "update the couple id-first_name/last_name/bio" do
require 'csv'
visit new_upload_url
file_path = Rails.root + "spec/fixtures/upload.csv"
attach_file('file', file_path)
click_button "Upload"
@post.reload
@post.email.should equal("[email protected]")
@post.first_name.should equal("nicolas")
@post.name.should equal("Alpi")
@post.bio.should equal("Sincerely believes sheep will dominate the world one day.")
end
scenario "File missing on upload" do
visit new_upload_url
click_button "Upload"
page.should have_content('File Missing')
end
end
Create a file in your spec/fixtures/upload.csv containing
Email, First Name, Last Name, Bio
nicolas@wealsodocookies.com, nicolas, Alpi, Sincerely believes sheep will dominate the world one day.
And we now have a simple test simulating the CSV upload. What’s next is the easy part, we can do to our upload method in Author controller
def upload
require 'csv'
if params[:file].blank?
flash[:notice] = "File missing"
redirect_to upload_path
else
file = params[:file].read
CSV.parse(file, headers: true, header_converters: :symbol).each do |row|
email, first_name, last_name, bio = row[0], row[1], row[2], row[3]
Author.update_all("first_name = '#{first_name}', last_name = '#{last_name}', bio = '#{bio}'", "email = '#{email}'")
end
redirect_to new_upload_url, :notice => "Upload successful"
end
end
And voila, we should have our test passing now.