You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rails控制器中将wicked_pdf生成的PDF上传至S3存储桶

Got it, let's work through this problem together. Heroku's filesystem is ephemeral—any files you save locally will disappear when your dyno restarts—so we can skip writing to public or pdfs directories entirely. Instead, we'll upload the PDF directly from the string generated by wicked_pdf to S3, no local file required. Here's a step-by-step solution:

1. Add the AWS SDK Gem

First, you'll need the AWS SDK for S3 to interact with your bucket. Add this to your Gemfile:

gem 'aws-sdk-s3'

Run bundle install to install it.

2. Configure S3 Credentials

You can set up your S3 credentials either using Rails credentials or environment variables (ideal for Heroku).

Option A: Rails Credentials

Run rails credentials:edit in your terminal and add your AWS details:

aws:
  access_key_id: YOUR_AWS_ACCESS_KEY
  secret_access_key: YOUR_AWS_SECRET_KEY
  region: YOUR_AWS_REGION # e.g., us-east-1
  bucket: YOUR_S3_BUCKET_NAME

Option B: Heroku Environment Variables

In your Heroku dashboard (or via CLI), set these config vars:

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_REGION
  • AWS_BUCKET

3. Update Your Controller Code

Replace your current file-saving logic with code that uploads directly to S3. Here's a complete example:

def generate_user_pdf
  # Generate the PDF string with wicked_pdf (add template/layout options if needed)
  pdf_content = render_to_string(
    pdf: "user_detail",
    template: "users/show" # Replace with your actual template path
  )

  # Initialize the S3 resource
  s3 = Aws::S3::Resource.new(
    access_key_id: Rails.application.credentials.dig(:aws, :access_key_id) || ENV['AWS_ACCESS_KEY_ID'],
    secret_access_key: Rails.application.credentials.dig(:aws, :secret_access_key) || ENV['AWS_SECRET_ACCESS_KEY'],
    region: Rails.application.credentials.dig(:aws, :region) || ENV['AWS_REGION']
  )

  # Define your custom S3 path (organize files however you want)
  # Example: Group by user ID and timestamp for uniqueness
  s3_file_path = "user_pdfs/#{current_user.id}/#{Time.now.strftime('%Y%m%d_%H%M%S')}_user_detail.pdf"

  # Upload the PDF content to S3
  begin
    s3_bucket = s3.bucket(Rails.application.credentials.dig(:aws, :bucket) || ENV['AWS_BUCKET'])
    s3_object = s3_bucket.object(s3_file_path)
    
    s3_object.put(
      body: pdf_content,
      content_type: 'application/pdf',
      acl: 'public-read' # Use 'private' if you don't want public access
    )

    # Get the URL to use (public URL or presigned URL for private files)
    pdf_url = s3_object.public_url # For public files
    # pdf_url = s3_object.presigned_url(:get, expires_in: 3600) # For private files (expires in 1 hour)

    # Optional: Save the URL to your database (e.g., current_user.update(pdf_url: pdf_url))
    flash[:success] = "PDF uploaded successfully! URL: #{pdf_url}"
  rescue Aws::S3::Errors::ServiceError => e
    flash[:error] = "Failed to upload PDF: #{e.message}"
  end

  redirect_to your_path
end

Key Notes:

  • No Local Files: We're using the raw pdf_content string directly, so we avoid Heroku's temporary filesystem limitations entirely.
  • Custom S3 Path: The s3_file_path variable lets you organize your PDFs in S3 however you like—group by user, date, or any other logic that makes sense for your app.
  • ACL Settings: Adjust the acl parameter based on your needs:
    • public-read: Anyone can access the PDF via its URL.
    • private: Only users with AWS credentials or a presigned URL can access it.
  • Error Handling: The begin-rescue block catches any S3-related errors, so you can notify the user if something goes wrong.

That's it! This approach will let you generate and store your PDFs in S3 without relying on Heroku's local filesystem.

内容的提问来源于stack exchange,提问作者Haseeb Ahmad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:58:36