DevelopmentWeb

Rails 3 CSV upload and tested with Capybara

By May 3, 2012 No Comments

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 => "nicolas@wealsodocookies.com",
                                 :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("nicolas@wealsodocookies.com")
      @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.