我如何干涸代码以从我的动作控制器和 rails 5 中的应用程序记录中导出不同的 CSV?

How can I dry up code to export different CSVs from my action controller and application record in rails 5?

我有一个应用程序,其唯一目的是播种数据文件并将数据添加到用户压缩和导出的不同 CSV 文件中。我的应用程序控制器充满了看起来像这样的行:

  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

我在应用程序控制器中有它,因为我在多个不同的领域使用它,包括创建单个 CSV 导出和创建内部有多个 zip 和 CSV 的复杂 zip 文件。

我尝试清理代码的一些事情包括:

我的申请记录同样糟糕,重复的行只是为了导出 CSV:

      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

对于应用程序记录,我尝试了与应用程序控制器列出的类似方法,但无济于事。同样,我使用应用程序记录中的代码而不是单个模型文件中的代码,因为我需要在网站的多个部分访问这些代码。

来自应用程序控制器的代码主要用于视图文件上的静态控制器和按钮。我需要能够创建文件集,如下所列,但也允许用户仅导出一个 CSV。

从静态控制器构建 zip 文件的示例:

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 到我的存储库,如果有帮助的话 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

我知道一定有比一遍又一遍地写这些相同的行更好的方法。代码有效,我的网站有效(令人惊讶),但如果任何经验丰富的开发人员看到存储库而不笑,我会感到尴尬。感谢您的帮助!

最后,我最终使用元编程来清理它。这是一个示例,为了简洁起见,我从数组中排除了一些项目:

  ["bundle", "attendee", "location", "membership", "client", "staff"].each do |new_method|
    define_method("#{new_method.pluralize}") do
      instance_variable_set("@#{new_method.pluralize}", new_method.camelcase.constantize.all)
      instance_var = instance_variable_get("@#{new_method.pluralize}")
      send_data instance_var.public_send("to_csv_#{new_method.pluralize}"), filename: "#{new_method.pluralize}.csv"
    end
  end

我能够从新创建的导出控制器中删除 30 个方法。这是上推更改后的代码https://github.com/atayl16/data-wizard/blob/0011b6cf8c1fe967d73a569fa573cedc52cb8c72/app/controllers/export_controller.rb