Created
June 6, 2011 03:58
-
-
Save nthj/1009723 to your computer and use it in GitHub Desktop.
Constituent Importer for Capvoice
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# constituent_importer.rb | |
# | |
# When the customer uploads an Excel file, | |
# we generate a unique ID for the file and | |
# store it on our AWS/S3 jobs bucket. | |
# | |
# Then we create a job with that unique ID, | |
# and our background workers execute the job as follows | |
class ConstituentImporter < Struct.new(:job_object_id) | |
extend ActiveSupport::Memoizable | |
include Capbot::Importer::Filterable # add before, after filters | |
include Capbot::Importer::Encodable # wraps the job, making sure our server doesn't get stuck in binary mode | |
include Capbot::Sourceable | |
include Capbot::Manageable # automatically scale our Heroku workers, saving us money | |
force_encoding 'ASCII-8BIT' # spreadsheets are binary files, not text | |
class InvalidJobObject < Exception; end | |
class NoColumnsFound < Exception; end | |
add_after_filter :delete_job_object | |
class << self | |
# use this in ImportController to make sure the customer uploaded a file | |
def validate_job_object form | |
raise InvalidJobObject if form.nil? || form.empty? || form[:excel].nil? || !File.size?(form[:excel].tempfile.path) | |
end | |
end | |
# translation magic | |
# guesses which Excel columns match up to our Capvoice database structure | |
def columnize row | |
return if @columns | |
@columns = { } | |
row.each_with_index do |label, column| | |
@columns[column] = case label | |
when /address/i then :address | |
when /city.*state/i then :city_and_state | |
when /city/i then :city | |
when /county/i then :county | |
when /email/i then :email | |
when /first/i then :first_name | |
when /last/i then :last_name | |
when /name/i then :name | |
when /title|office/i then :office | |
when /phone|number/i then :phone | |
when /state/i then :state | |
when /postal|code|zip/i then :zip_code | |
end | |
end | |
raise NoColumnsFound if @columns.empty? | |
@columns | |
end | |
def import row | |
attributes = { } | |
row.each_with_index do |value, column| | |
attributes.merge!(@columns[column] => value) if @columns[column] | |
end | |
# we should refactor this a bit | |
attributes[:city] = attributes[:city_and_state].split(',').first if attributes[:city_and_state] unless attributes[:city] | |
attributes[:name] = [attributes[:first_name], attributes[:last_name]].compact.join(' ') unless attributes[:name] | |
attributes[:state] = attributes[:city_and_state].split(',').last if attributes[:city_and_state] unless attributes[:state] | |
attributes[:state] = State.find_by_name(attributes[:state]).abbreviation if attributes[:state] && State.find_by_name(attributes[:state]) | |
account.constituents.merge_or_create attributes | |
end | |
def perform | |
spreadsheet.worksheets.each do |sheet| | |
reset_columns | |
sheet.each do |row| | |
columnize row or import row | |
end | |
end | |
end | |
protected | |
def account | |
User.find(JobObject.unique_number_from_object_id(job_object_id)).account | |
end | |
memoize :account | |
def delete_job_object | |
JobObject.delete job_object_id | |
end | |
def reset_columns | |
@columns = nil | |
end | |
def source | |
JobObject.source job_object_id | |
end | |
def spreadsheet | |
Spreadsheet.client_encoding = @@encoding | |
Spreadsheet.open stream | |
end | |
memoize :spreadsheet | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment