Skip to content

Write a simple importer

Bess Sadler edited this page Feb 4, 2019 · 20 revisions

Simple Importer Goals:

  • Write a very simple CSV importer
  • Be able to point to the parts of the importer

Setup

(OPTIONAL) Save your current changes

If you have changes in your current branch -- you can check on this via git status -- you'll want to save those before starting this lesson (which uses a separate branch):

  • git checkout -b your_branch_name
  • git add .
  • git commit -m 'checkpoint before beginning simple importer'

Check out working branch

git checkout importer_setup

NOTE: If you make experimental changes and want to get back to the minimal code state necessary to run this lesson, you can check the starting code out again using:
git checkout importer_setup

1. Write a test for the importer

As you've come to expect by now, we're going to write a test for our simple importer first. Make a directory in the spec folder for our importer tests:

  mkdir spec/importers

Now, make a file in that folder called simple_importer_spec.rb and paste the following content into it:

# frozen_string_literal: true

require 'rails_helper'
require 'active_fedora/cleaner'

RSpec.describe SimpleImporter do
  let(:one_line_example)       { 'spec/fixtures/csv_files/one_line_example.csv' }
  let(:three_line_example)     { 'spec/fixtures/csv_files/three_line_example.csv' }

  before do
    DatabaseCleaner.clean
    ActiveFedora::Cleaner.clean!
  end

  it "imports a csv" do
    expect { SimpleImporter.new(three_line_example).import }.to change { Image.count }.by 3
  end

  it "puts the title into the title field" do
    SimpleImporter.new(one_line_example).import
    imported_image = Image.first
    expect(imported_image.title.first).to eq 'A Cute Dog'
  end

  it "puts the url into the source field" do
    SimpleImporter.new(one_line_example).import
    imported_image = Image.first
    expect(imported_image.source.first).to eq 'https://www.pexels.com/photo/animal-blur-canine-close-up-551628/'
  end

  it "creates publicly visible objects" do
    SimpleImporter.new(one_line_example).import
    imported_image = Image.first
    expect(imported_image.visibility).to eq 'open'
  end

  it "attaches a file" do
    SimpleImporter.new(one_line_example).import
    imported_image = Image.first
    expect(imported_image.members.first).to be_instance_of(FileSet)
    expect(imported_image.members.first.title.first).to eq 'dog.jpg'
  end
end

Run your test: rspec spec/importers/simple_importer_spec.rb. You should see an error that says something like:

NameError:
  uninitialized constant SimpleImporter

2. Make a SimpleImporter class

Let's write just enough of our importer to make that error message change. Make a folder called importers in the app folder (mkdir app/importers), and within that make a file called simple_importer.rb. Paste this into it:

class SimpleImporter

  def initialize(file)
    @file = file
    @user = ::User.batch_user
  end

  def import
  end
end

Now run your test again (rspec spec/importers/simple_importer_spec.rb). The test will still fail, but for different reasons. Now it is able to find a class called SimpleImporter, but calling it does not produce the expected results. Writing our test first and making small changes to behavior, while running our test over and over to observe how it behaves is a good TDD habit that we're practicing here.

3. Process the CSV and make an object with metadata

Ideally we would make just one test pass at at time, but I am compressing this exercise because we are short on time. Replace your simple_importer.rb file with this one:

require 'csv'

class SimpleImporter

  def initialize(file)
    @file = file
    @user = ::User.batch_user
  end

  def import
    CSV.foreach(@file) do |row|
      image = Image.new
      image.depositor = @user.email
      image.title << row[1]
      image.source << row[2]
      image.visibility = Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC
      image.save
    end
  end
end

Note: You can see the changes we made in this section on github.

For discussion:

  1. Why create subdirectories in the fixtures folder?
  2. What other data can you imagine adding to the fixtures folder over time?
  3. What makes a good fixture object?