Skip to content

Instantly share code, notes, and snippets.

@goofansu
Last active January 22, 2023 13:18
Show Gist options
  • Save goofansu/f42f0e19fc35a686c8217cfea81bdb5b to your computer and use it in GitHub Desktop.
Save goofansu/f42f0e19fc35a686c8217cfea81bdb5b to your computer and use it in GitHub Desktop.
# app/models/contact_export.rb
class ContactExport < ApplicationRecord
after_create_commit :process_later
def process
LeadSubmission::Exporter.new(self).perform
end
private
def process_later
ContactExporterWorker.perform_async(self.id)
end
end
# app/workers/contact_exporter_worker.rb
class ContactExporterWorker
include Sidekiq::Worker
sidekiq_options queue: :export
def perform(contact_export_id)
contact_export = ContactExport.find(contact_export_id)
contact_export.process
end
end
  • The domain problem is users can export LeadSubmissions to CSVs and Excels.
  • LeadSubmission::Exportable concern is added to encapsulate the logic for exportable fields.
    • When rendering the export page, BASE_FIELDS are pre-selected.
    • Call export_sections to get all the exportable fields in the form of sections, which is mapped to the client data structure.
  • Move Service::Exporter::ContactExporter to LeadSubmission::Exporter for coheresiveness, which means code for exporting LeadSubmissions is in the same place: app/models/lead_submission/*.
# app/models/lead_submission/exportable.rb
module LeadSubmission::Exportable
extend ActiveSupport::Concern
SECTION_CONTACT = 'contact'
SECTION_EXTRA = 'extra'
SECTION_CRM = 'crm'
CATEGORY_BASE = 'base'
CATEGORY_STUDENT = 'student'
CATEGORY_EXTRA = 'extra'
SECTIONS = {
SECTION_CONTACT => [
CATEGORY_BASE,
CATEGORY_STUDENT,
],
SECTION_EXTRA => [
CATEGORY_EXTRA,
],
SECTION_CRM => [],
}
CATEGORIES = {
CATEGORY_BASE => [
{ id: 'first_name' },
{ id: 'last_name' },
{ id: 'email' },
{ id: 'phone_number' },
{ id: 'representative_name' },
{ id: 'crm_campaign_name' },
{ id: 'agent_name', condition: ->(school) { school.enable_agent_mode? } },
{ id: 'agency_name', condition: ->(school) { school.enable_agent_mode? } },
{ id: 'created_date' },
],
CATEGORY_STUDENT => [
{ id: 'student_first_name' },
{ id: 'student_last_name' },
{ id: 'student_gender_name' },
{ id: 'student_birthday' },
{ id: 'apply_grade_name' },
{ id: 'apply_academic_year_name' },
],
CATEGORY_EXTRA => [
{ id: 'id' },
{ id: 'openid', condition: ->(school) { school.has_wechat_contact_form_feature? } },
{ id: 'unionid', condition: ->(school) { school.has_wechat_contact_form_feature? } },
],
}
# BASE_FIELDS are pre-selected automatically.
BASE_FIELDS = %w(
first_name
last_name
email
)
class_methods do
def export_sections(school)
SECTIONS.map do |section, categories|
section_data(section, categories, school)
end
end
private
def section_name(section)
I18n.t(section, scope: 'admin.export.contacts.section')
end
def category_name(category)
I18n.t(category, scope: 'admin.export.contacts.category')
end
def field_name(field)
I18n.t(field[:id], scope: 'admin.export.contacts.contact_field')
end
def section_data(section, categories, school)
title = section_name(section)
form_pages = if section == SECTION_CRM
crm_form_pages(school)
else
form_pages_by_categories(categories, school)
end
{ id: section, title: title, form_pages: form_pages }
end
def form_pages_by_categories(categories, school)
categories.map do |category|
name = category_name(category)
fields = fields_by_category(category, school)
{ id: category, name: name, fields: fields }
end
end
def fields_by_category(category, school)
CATEGORIES[category].select do |field|
field[:condition].blank? || field[:condition].call(school)
end.map do |field|
field[:name] = field_name(field)
field
end
end
def crm_form_pages(school)
Service::Exporter::CRMContactField.new(school).grouped_fields
end
end
# Following are methods to get field values
def name
[first_name, last_name].join(' ')
end
def gender_name
I18n.t(gender, scope: 'gender')
end
# ...
end
# app/models/lead_submission/exporter.rb
class LeadSubmission::Exporter
attr_reader :contact_export
delegate :school, :fields, :contact_ids, to: :contact_export
def initialize(contact_export)
@contact_export = contact_export
end
def perform
case contact_export.format
when 'csv'
export_csv { |file| upload_and_notify(file) }
when 'xlsx'
export_xlsx { |file| upload_and_notify(file) }
else
raise 'Unknown format!'
end
end
private
# ...
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment