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

如何在Ruby on Rails后端生成Chart.js图表并作为邮件附件发送

Absolutely! You can render Chart.js charts server-side in Rails, save them as images, and attach them to emails—here are a couple of reliable approaches to pull this off:

Approach 1: Use Puppeteer (Headless Chrome)

Since Chart.js relies on a browser's JavaScript engine, using a headless browser like Chrome (via Puppeteer) is the most flexible way to render charts server-side. Here's how to set it up:

Step 1: Add Dependencies

First, add the puppeteer-ruby gem to your Gemfile:

gem 'puppeteer-ruby'

Run bundle install, then make sure your server has Chrome/Chromium installed. For Ubuntu-based servers, install it with:

sudo apt-get install chromium-browser

Step 2: Create a Chart HTML Template

Make an ERB template that includes Chart.js and your chart configuration. For example, app/views/charts/email_chart.html.erb:

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0"></script>
</head>
<body>
  <canvas id="myChart" width="800" height="400"></canvas>
  <script>
    const ctx = document.getElementById('myChart').getContext('2d');
    new Chart(ctx, {
      type: '<%= @chart_type %>',
      data: <%= @chart_data.to_json %>,
      options: <%= @chart_options.to_json %>
    });
  </script>
</body>
</html>

Step 3: Write a Service to Generate the Image

Create a service class to render the template, load it in Puppeteer, and take a screenshot:

# app/services/chart_generator_service.rb
require 'puppeteer'

class ChartGeneratorService
  def self.generate(chart_type:, chart_data:, chart_options: {})
    # Render the ERB template to HTML
    html = ApplicationController.render(
      template: 'charts/email_chart',
      locals: {
        chart_type: chart_type,
        chart_data: chart_data,
        chart_options: chart_options
      }
    )

    # Create a temporary file to store the image
    temp_file = Tempfile.new(['chart', '.png'])
    temp_file.close

    # Launch headless Chrome and take a screenshot
    Puppeteer.launch(headless: :new) do |browser|
      page = browser.new_page
      page.set_content(html)
      # Wait a moment for Chart.js to finish rendering (adjust timeout as needed)
      page.wait_for_timeout(1500)
      # Capture the canvas area as a PNG
      page.screenshot(path: temp_file.path, clip: { x: 0, y: 0, width: 800, height: 400 })
    end

    temp_file
  end
end

Step 4: Attach the Image to an Email

Use the service in your mailer to generate the chart and attach it:

# app/mailers/chart_mailer.rb
class ChartMailer < ApplicationMailer
  def send_chart(recipient, chart_type, chart_data, chart_options = {})
    # Generate the chart image
    chart_file = ChartGeneratorService.generate(
      chart_type: chart_type,
      chart_data: chart_data,
      chart_options: chart_options
    )

    # Attach the file to the email
    attachments['analytics_chart.png'] = File.read(chart_file.path)

    # Send the email
    mail(to: recipient, subject: 'Your Requested Chart') do |format|
      format.html { render plain: 'Check out your chart attached below!' }
    end

    # Clean up the temporary file
    chart_file.unlink
  end
end

Approach 2: Use a Third-Party Chart API (No Browser Required)

If you don't want to manage a headless browser setup, use a free API to render Chart.js charts directly to images. This is great for simple use cases:

# Example service using a chart API
class ChartApiGeneratorService
  def self.generate(chart_config)
    encoded_config = URI.encode_www_form_component(chart_config.to_json)
    image_url = "https://quickchart.io/chart?c=#{encoded_config}"

    temp_file = Tempfile.new(['chart', '.png'])
    temp_file.binmode
    temp_file.write(URI.open(image_url).read)
    temp_file.close

    temp_file
  end
end

# Usage in mailer
chart_config = {
  type: 'line',
  data: { labels: ['Jan', 'Feb', 'Mar'], datasets: [{ data: [10, 25, 15] }] }
}
chart_file = ChartApiGeneratorService.generate(chart_config)

Note: This relies on an external service, so avoid sending sensitive data via this method, and check the API's rate limits.

Key Considerations

  • Background Processing: Generating images can be slow—use a background job (like Sidekiq) to offload this work instead of running it in a web request.
  • Server Deployment: For Heroku, add the Chromium buildpack and set the env var PUPPETEER_EXECUTABLE_PATH=/app/.apt/usr/bin/chromium-browser.
  • Performance: Adjust the Puppeteer wait timeout based on how complex your charts are—you can also listen for Chart.js's animationComplete event instead of using a fixed delay for more reliability.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 10:11:05