rubyruby-on-rails-3amazon-s3axlsx

How to upload an excel file into S3 bucket using ruby on rails


In our rails 6 project I want to upload excel file into S3 bucket and send file link to email and provide download xls feature from email. Please help me.

I have generated the excel file using the code below, and also set S3 configuration in our project

 xlsx = GenerateSpreadsheetService.new(all_data, file_name).call

Now my question is that how to upload the above excel file into S3 bucket and send file link to email and provide download xls feature from email

class ImportCsvDataJob < ApplicationJob
  queue_as :default


  def perform(file_name, column)
    begin
      keywords = []
      all_data = []

      file_path = get_file_path(file_name)
      spreadsheet = Roo::Excelx.new(file_path)
      (2..spreadsheet.last_row).each do |i|
        keywords << {"language_code": "en", "location_code": 2840, "keyword": "allintitle: #{spreadsheet.row(i)}"}
      end

      response = GetTaskService.new(keywords).call 
      response["tasks"].map{|task|
        keyword = task["data"]["keyword"].gsub('allintitle: ','')
        result = GetTaskService.new.get_values(task["id"])
        all_data << {keyword: keyword.to_s, value: result["tasks"][0]["result"][0]["se_results_count"]}
      } 
      ## Create records  
      CsvImport.create(all_data)
      ## Generate excel file
      xlsx = GenerateSpreadsheetService.new(all_data, file_name).call
      ## send email
      SendEmailJob.perform_now(xlsx, file_name) 
      ## remove temp storage file after processing
      File.delete(Rails.root + "public/spreadsheets/#{file_name}")
    rescue Exception => e
      Rails.logger.info "--error-----#{e.message}--"
    end
  end
end
class GenerateSpreadsheetService
  def initialize(data = [], file_name)
    @data = data
    @file_name = file_name
  end

  def call
    ActionController::Base.new().render_to_string(template: "csv_imports/template.xlsx.axlsx", layout: false, formats: [:axlsx], locals: {:data => @data})
  end
end
class SendEmailJob < ApplicationJob
  queue_as :default

  def perform(xlsx, file_name)
    SendEmailService.new(xlsx, file_name).call
  end
end
class SendEmailService
    def initialize(xlsx, file_name)
        @xlsx = xlsx
        @email = "test@example.com"
        @subject = "excel file"
        @file_name = file_name
    end

    def call
        KeywordMailer.send_csv(@email, @subject, @xlsx, @file_name).deliver_now!
    end
end

Solution

  • How did I solved this problem?

    1. Generate excel sheet

       time = Time.zone.now.strftime("%Y%m%d%H%M%S")
       xlsx = GenerateSpreadsheetService.new(all_data, file_name).call
    
    1. Create an empty directory

       path = Tempfile.new("data_#{time}.xlsx").path
    
    1. Write the excel file into this directory

       file = File.open(path,"wb") {|f| f.write(xlsx) }
       s3 = Aws::S3::Resource.new(region: APP_CONFIG["s3_region"], credentials: Aws::Credentials.new(APP_CONFIG["s3_access_key"], APP_CONFIG["s3_secret_key"]))
       obj = s3.bucket(APP_CONFIG["s3_bucket"]).object("data_#{time}.xlsx")
       obj.upload_file(path)
       presigned_url = obj.presigned_url(:put, bucket: APP_CONFIG["s3_bucket"], key: "data_#{time}.xlsx", expires_in: 604800)
    
    1. save public_url and presigned_url

       FileUrl.create(key: "data_#{time}.xlsx", file_public_url: obj.public_url, file_presigned_url: presigned_url) if presigned_url.present?