사용자 데이터를 CSV로 내보내고 Ruby on Rails로 이메일 보내기

14790 단어 rubyrails
GDPR을 준수하기 위해 앱에 있는 사용자 데이터를 내보내야 하는 경우가 있습니다. 그래서 여기에서는 사용자 데이터를 CSV 파일로 내보내고 이메일에 첨부하거나 ActiveStorage 및 S3에 업로드하는 방법을 설명하겠습니다.

이 예제 코드에는 사용자가 은행 계좌 이름, 통화 및 거래 날짜와 함께 금융 거래를 저장하는 앱이 있습니다.

Rails 임시 디렉토리에 임시 파일을 만든 다음 이메일 또는 저장을 위해 SendGrid로 보냅니다. 데이터를 임시 CSV 파일에 추가한 다음 export_to_storage를 호출하여 ActiveStorage에 저장하고 send_email를 호출하여 CSV 파일이 첨부된 사용자 이메일을 보냅니다.

this article에서 SendGrid를 사용하여 첨부 파일이 있는 이메일을 보내는 방법을 이미 설명했습니다.
app/services/export_services/export_transaction_service.rb
# frozen_string_literal: true

# app/services/export_services/export_transaction_service.rb
# Example:
#   ExportServices::ExportTransactionService.new({ user: User.last}).call
#   ExportServices::ExportTransactionService.new({ user: User.last, from_date: '2022-01-01', to_date: '2022-09-01'}).call
module ExportServices
  # ExportTransactionService
  class ExportTransactionService
    # initialize the service with user, from_date and to_date and setting transactions accordingly
    def initialize(params) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
      @user = params[:user]
      @from_date = params[:from_date] ? params[:from_date].to_date : 10.years.ago # -Infinity
      @to_date = params[:to_date] ? params[:to_date].to_date : Time.zone.now
      @transactions = @user.transactions.where(transaction_date: @from_date..@to_date)
                           .joins(:account, :category).kept.order(transaction_date: :desc)
    end

    # service work when call method is called
    def call
      return if @transactions.length.zero?

      generate_csv_file
      # export_to_storage
      send_email
    end

    # This method creates a temp CSV file and fills data based on initialized transactions
    def generate_csv_file # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
      @tempfile = Tempfile.new(["export_#{Time.zone.now.strftime('%Y%m%d%H%M%S')}_#{@user.id}", '.csv']).tap do |file|
        CSV.open(file, 'wb') do |csv|
          # CSV Header Row
          csv << %w[Date Description Type Amount Currency Category Account]

          # CSV Rows, each row representing a transaction
          @transactions.find_each do |transaction|
            csv << [
              transaction.transaction_date.to_date.to_s,
              transaction.description,
              transaction.transaction_type == 'income' ? 'Income' : 'Expense',
              transaction.value.to_f.round(2),
              transaction.account.currency.code,
              transaction.category.name,
              transaction.account.name,
            ]
          end
        end
      end
    end

    # Thios method adds the tempfile to ActiveStorage and hence to S3 service if attached
    # I have attached s3 to production environment
    # returns url of the uploaded CSV File
    def export_to_storage # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
      # Document Model `has_attached_file :doc` and `user has_many :documents` and `document belongs_to :user`
      document = Document.new(user: @user)
      document.doc.attach(
        io: @tempfile,
        filename: @tempfile.path.split('/').last,
        content_type: 'application/csv'
      )
      document.save!
      @file_url = if Rails.env.production?
                    # returns s3 public url
                    Rails.application.routes.url_helpers.rails_public_blob_url(@document.doc)
                  else
                    # return local url
                    Rails.application.routes.url_helpers.rails_blob_url(@document.doc)
                  end
    end

    # This method sends email with temp file attached
    # https://gist.github.com/sulmanweb/eab697301cf8209572c5a95af6543b3a
    # https://sulmanweb.com/send-emails-using-sendgrid-sdk-for-ruby-on-rails-using-dynamic-sendgrid-email-templates/
    def send_email # rubocop:disable Metrics/MethodLength
      EmailJob.new.perform(
        @user.id,
        { name: @user.name },
        ENV.fetch('EXPORT_TEMPLATE', nil),
        [
          {
            file: @tempfile.path,
            type: 'application/csv',
            name: @tempfile.path.split('/').last,
            content_id: 'export_file'
          }
        ]
      )
    end
  end
end


GitHub Gist

11행에서 매개변수로 서비스를 초기화합니다. 필수는 사용자이고 선택은 날짜 범위입니다. 초기화 후 제공된 사용자의 트랜잭션을 가져옵니다.

20행의 call 메서드는 사용자에게 트랜잭션이 하나 이상 있는지 확인한 다음 generate_csv_file를 호출하여 사용자의 트랜잭션으로 임시 CSV 파일을 만든 다음 send_email를 사용하여 첨부 파일과 함께 이메일을 보냅니다.

s3에 업로드하려는 경우 54행의 메서드export_to_storage는 선택 사항입니다. 이 경우 이 메서드는 s3의 URL 또는 파일의 로컬 저장소를 반환합니다.

코드에서 이 서비스를 호출하는 예는 다음과 같습니다.

ExportServices::ExportTransactionService.new({ user: User.last}).call



ExportServices::ExportTransactionService.new({ user: User.last, from_date: '2022-01-01', to_date: '2022-09-01'}).call


의견 섹션에서 더 많은 질문을 자유롭게 하십시오.


행복한 코딩!

좋은 웹페이지 즐겨찾기