I have an app whose sole purpose is to seed data files and add the data to different CSVs which are zipped and exported by the user. My application controller is filled with lines that all look like this:
def export_tips
@appointments = Appointment.order('service_id')
send_data @appointments.to_csv_tips, filename: 'tips.csv'
end
def export_ticketpayments
@appointments = Appointment.order('service_id')
send_data @appointments.to_csv_ticketpayments, filename: 'ticketspaymentitems.csv'
end
def export_batchmanifest
@batchmanifests = Batchmanifest.all
send_data @batchmanifests.to_csv_batchmanifest, filename: "batch_manifest-#{Date.today}.csv"
end
def export_pets
@clients = Client.all
send_data @clients.to_csv_pets, filename: 'pets.csv'
end
def export_clients
@clients = Client.all
send_data @clients.to_csv_clients, filename: 'clients.csv'
end
I have it in the application controller because I used it in multiple different areas including creating single CSV exports and creating complex zip files with multiple zips and CSVs inside.
Some things that I have tried to cleanup the code include:
- Different variables of this: def csv_export (model, filename) @model.pluralize = (model.titleize).all send_data @model.pluralize.filename, filename: filename end
- Having each one in its own controller (could not access them from different views and other controllers easily)
- I also tried to figure out how to create my own module, but was unable to do so.
My application record is just as bad with repeated lines simply meant to export the CSVs:
def self.to_csv_appointments
attributes = %w[appointment_id location_id employee_id client_id child_id notes
has_specific_employee start_time end_time]
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |appointment|
csv << attributes.map { |attr| appointment.send(attr) }
end
end
end
def self.to_csv_appointmentservices
attributes = %w[appointment_id service_id price duration]
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |appointment|
csv << attributes.map { |attr| appointment.send(attr) }
end
end
end
def self.to_csv_tickets
attributes = %w[ticket_id location_id client_id ticket_status employee_id
employee_id start_time]
headers = %w[ticket_id location_id client_id status employee_id
closed_by_employee_id closed_at]
CSV.generate(headers: true) do |csv|
csv << headers
all.each do |appointment|
csv << attributes.map { |attr| appointment.send(attr) }
end
end
end
For the application record, I have tried similar methods as those listed for the application controller, but to no avail. Again, I use the code in application record instead of in the individual model files because I need to access these in multiple parts of the site.
The code from the application controller is used mostly in the static controller and buttons on the view files. I need the ability to create the file sets, as listed below, but also allow the user to export just one CSV.
Examples from static controller to built the zip files:
def create_appointments_zip
file_stream = Zip::OutputStream.write_buffer do |zip|
@appointments = Appointment.order('service_id')
zip.put_next_entry "appointment_manifest.csv"; zip << File.binread("#{Rails.root}/app/assets/csvs/appointment_manifest.csv")
zip.put_next_entry "appointments.csv"; zip << @appointments.to_csv_appointments
zip.put_next_entry "appointment_services.csv"; zip << @appointments.to_csv_appointmentservices
zip.put_next_entry "appointment_statuses.csv"; zip << @appointments.to_csv_appointmentstatuses
end
file_stream.rewind
File.open("#{Rails.root}/app/assets/csvs/appointments.zip", 'wb') do |file|
file.write(file_stream.read)
end
end
def export_salonset
create_appointments_zip
create_tickets_zip
create_inventory_zip
create_memberships_zip
file_stream = Zip::OutputStream.write_buffer do |zip|
@saloncategories = Saloncategory.all
@salonservices = Salonservice.all
@clients = Client.all
@locations = Location.all
@salonpricings = Salonpricing.all
@staffs = Staff.order("location_id")
zip.put_next_entry "batch_manifest.csv"; zip << File.binread("#{Rails.root}/app/assets/csvs/batch_manifest_simple_salon.csv")
zip.put_next_entry "categories.csv"; zip << @saloncategories.to_csv_saloncategories
zip.put_next_entry "clients.csv"; zip << @clients.to_csv_clients
zip.put_next_entry "employees.csv"; zip << @staffs.to_csv_staff
zip.put_next_entry "locations.csv"; zip << @locations.to_csv_locations
zip.put_next_entry "pricings.csv"; zip << @salonpricings.to_csv_pricings
zip.put_next_entry "services.csv"; zip << @salonservices.to_csv_salonservices
zip.put_next_entry "appointments.zip"; zip << File.binread("#{Rails.root}/app/assets/csvs/appointments.zip")
zip.put_next_entry "inventories.zip"; zip << File.binread("#{Rails.root}/app/assets/csvs/inventories.zip")
zip.put_next_entry "tickets.zip"; zip << File.binread("#{Rails.root}/app/assets/csvs/tickets.zip")
zip.put_next_entry "addonmappings.csv"; zip << File.binread("#{Rails.root}/app/assets/csvs/addonmappings.csv")
end
file_stream.rewind
respond_to do |format|
format.zip do
send_data file_stream.read, filename: "salon_set.zip"
end
end
file_stream.rewind
File.open("#{Rails.root}/app/assets/csvs/salon_set.zip", 'wb') do |file|
file.write(file_stream.read)
end
end
Link to my repository, if that is helpful https://github.com/atayl16/data-wizard/blob/master/app/controllers/application_controller.rb https://github.com/atayl16/data-wizard/blob/master/app/models/application_record.rb
I know there must be a better way than writing these same lines over and over. The code works, my site works (amazingly), but I would be embarrassed for any seasoned developer to see the repository without laughing. Any help is appreciated!