简体   繁体   中英

Redirect to another endpoint with large data - Rails/Ruby

I have a doubt about showing a generated CSV file to the user (with a large amount of data). So here is the task I have to do.

App: I have a film that has many characters.

Task:

  • allow users to upload characters via CSV (ok, done)
  • if there are errors, show them for each row (ok, done)
  • in the results page, also show a link to a new CSV file only with the remaining characters - the ones that couldn't be created ( I'm stuck here )

Here is part of my code (upload method):

def upload
    saved_characters = []
    characters_with_errors = []
    errors = {}

    begin
      CSV.parse(params[:csv].read, **csv_options) do |row|
        row_hash = clear_input(row.to_h)
        new_character = Character.new(row_hash)

        if new_character.save
          add_images_to(new_character, row)
          saved_characters << new_character
        else
          characters_with_errors << new_character
          errors[new_character.name] = new_character.errors.full_messages.join(', ')
        end
      end
    rescue CSV::MalformedCSVError => e
      errors = { 'General error': e.message }.merge(errors)
    end

    @upload = {
      errors: errors,
      characters: saved_characters,
      characters_with_errors: characters_with_errors
    }
  end

The issue: large amount of data

In the end, the upload.html.erb almost everything works fine, it shows the results and errors per column BUT I'm not sure how create a link on this page to send the user to the new CSV file (only with characters with errors). If the link sends the user to another method / GET endpoint (for the view with CSV format), how can I send such a large amount of data (params won't work because they will get too long)? What would be the best practice here?

You can use a session variable to store the data, and then redirect to a new action to download the file. In the new action, you can get the data from the session variable, and then generate the CSV file.

For example, In the upload action, you can do something like this:

session[:characters_with_errors] = characters_with_errors

redirect_to download_csv_path

In the download_csv action, you can do something like this:

characters_with_errors = session[:characters_with_errors]

session[:characters_with_errors] = nil

respond_to do |format|
  format.csv { send_data generate_csv(characters_with_errors) }
end

In the generate_csv method, you can do something like this:

def generate_csv(characters_with_errors)
  CSV.generate do |csv|
    csv << ['name', 'age' ]
    characters_with_errors.each do |character|
      csv << [character.name, character.age]
    end
  end
end

Another option, you can use a temporary file to store the data and then send the user to the new CSV file. Here is an example:

  def upload
      saved_characters = []
      characters_with_errors = []
      errors = {}
  
      begin
        CSV.parse(params[:csv].read, **csv_options) do |row|
          row_hash = clear_input(row.to_h)
          new_character = Character.new(row_hash)
  
          if new_character.save
            add_images_to(new_character, row)
            saved_characters << new_character
          else
            characters_with_errors << new_character
            errors[new_character.name] = new_character.errors.full_messages.join(', ')
          end
        end
      rescue CSV::MalformedCSVError => e
        errors = { 'General error': e.message }.merge(errors)
      end
  
      @upload = {
        errors: errors,
        characters: saved_characters,
        characters_with_errors: characters_with_errors
      }
  
      respond_to do |format|
        format.html
        format.csv do
          # Create a temporary file
          tmp = Tempfile.new('characters_with_errors')
          # Write the CSV data to the temporary file
          tmp.write(characters_with_errors.to_csv)
          # Send the user to the new CSV file
          send_file tmp.path, filename: 'characters_with_errors.csv'
          # Close the temporary file
          tmp.close
        end
      end
    end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM