The following is an example of file importing and parsing in Ruby using object-oriented techniques such as duck typing and dependency injection.
Inject a CSVParser
dependency into a the Importer
# app/controllers/contact_imports_controller.rb:
class ContactImportsController < ApplicationController
def new
@importer = Importer.new
end
def create
@importer = Importer.new(
parser: CSVParser.new(import_file),
import_type: import_type
)
@importer.import
respond_with(@importer, location: contacts_path)
end
private
def import_file
params[:importer][:file]
end
def import_type
params[:importer][:import_type]
end
end
A given parser
must respond to rows
and an instance of the given import_type
must respond to create
# app/models/importer.rb
class Importer
include ActiveModel::Validations
include ActiveModel::Conversion
VALID_IMPORT_TYPES = ['contact']
validates :import_type, inclusion: { in: VALID_IMPORT_TYPES }
attr_reader :parser, :import_type
def initialize(attributes={})
@parser = attributes[:parser]
@import_type = attributes[:import_type]
end
def import
if valid?
rows.each do |row|
import_factory.create(row)
end
end
end
private
def rows
parser.rows
end
def import_factory
import_type.to_s.constantize
end
end
A Contact
responds to create
:
# app/models/contact.rb:
class Contact < ActiveRecord::Base
end
A CSVParser
responds to rows
:
# app/models/csv_parser.rb:
class CSVParser
initialize(csv_file)
@csv_file = csv_file
end
def rows
# code that parses the CSV file and returns an array of hashes
end
end
To import XML files instead of CSV files, replace the CSV parser with another object that responds to rows
.
# app/models/xml_parser.rb
class XMLParser
def initialize(xml_file)
@xml_file = xml_file
end
def rows
# code that parses the XML file and returns an array of hashes
end
end
Takeaways
- Create small objects with single responsibilities
- Keep public interfaces consistant
- Send messages between collaborating objects without querying type
What’s next
Detect emerging problems in your codebase with Ruby Science. We’ll deliver solutions for fixing them, and demonstrate techniques for building a Ruby on Rails application that will be fun to work on for years to come.