DEV Community

Germán Alberto Gimenez Silva
Germán Alberto Gimenez Silva

Posted on • Originally published at rubystacknews.com on

Automating Document Generation with AI in Ruby on Rails

June 3, 2025

In modern software projects, automating routine tasks is crucial to speed up delivery and reduce human error. One great example is document generation —whether it’s product requirement documents (PRDs), proposals, or presentations.

Recently, I worked on a system that uses AI to generate structured content from conversations, then outputs documents in multiple formats like Word (.odt), PowerPoint (.pptx), Markdown (.md), and more. The architecture leverages conversational AI to generate structured content, and it’s fully adaptable to Ruby on Rails. Here’s how you can build such a system.


Get in Touch & Explore Services

If you’re interested in AI-powered document automation, Ruby on Rails development, or want to streamline your workflows with expert help, we’re here for you!

Contact Us


How It Works: The Architecture


User Input (Q&A + files)
        ↓
Conversational AI (OpenAI)
        ↓
Structured JSON PRD (document sections)
        ↓
Output Generators:
  ├─ DOCX (Word templates)
  ├─ PPTX (PowerPoint templates)
  ├─ Markdown (MD templates)
  ├─ YAML (configuration/data serialization)
  ├─ ODT (OpenDocument Text)
  ├─ PDF (final polished document)
  └─ TXT (plain text export)
        ↓
Export & Delivery (files to users)

Enter fullscreen mode Exit fullscreen mode

This flow ensures clear separation between content generation and format rendering , making it scalable and maintainable.


Ruby on Rails: Sample Implementation

Article content
Generation Using Templates

1. Conversational AI Client

Use the ruby-openai gem to interact with OpenAI’s API:


require 'openai'

class AiPrdService
  def initialize(user_prompt)
    @client = OpenAI::Client.new(access_token: ENV['OPENAI_API_KEY'])
    @user_prompt = user_prompt
  end

  def generate_prd_json
    response = @client.chat(
      parameters: {
        model: "gpt-4o-mini",
        messages: [
          { role: "system", content: "You are an AI assistant that generates structured PRDs." },
          { role: "user", content: @user_prompt }
        ],
        temperature: 0.7
      }
    )

    # Extract JSON from response (assuming AI outputs JSON)
    prd_content = JSON.parse(response.dig("choices", 0, "message", "content"))
    prd_content
  rescue JSON::ParserError => e
    Rails.logger.error "Failed to parse AI response: #{e.message}"
    nil
  end
end

Enter fullscreen mode Exit fullscreen mode

2. DOCX Generation Using Templates

You can use the caracal gem to create Word documents:


require 'caracal'

class DocxGenerator
  def initialize(prd_json)
    @prd_json = prd_json
  end

  def generate_docx(output_path)
    Caracal::Document.save(output_path) do |docx|
      docx.h1 @prd_json['title']
      @prd_json['sections'].each do |section|
        docx.h2 section['heading']
        docx.p section['content']
      end
    end
  end
end

Enter fullscreen mode Exit fullscreen mode

3. Markdown Generator Example

A simple template rendering can be done with ERB:


class MarkdownGenerator
  TEMPLATE = <<~MD
    # <%= @prd_json['title'] %>

    <% @prd_json['sections'].each do |section| %>
    ## <%= section['heading'] %>

    <%= section['content'] %>

    <% end %>
  MD

  def initialize(prd_json)
    @prd_json = prd_json
  end

  def generate_markdown
    ERB.new(TEMPLATE).result(binding)
  end
end

Enter fullscreen mode Exit fullscreen mode

4. YAML Export for Configurations or Data Sharing


require 'yaml'

class YamlGenerator
  def initialize(prd_json)
    @prd_json = prd_json
  end

  def generate_yaml(output_path)
    File.write(output_path, @prd_json.to_yaml)
  end
end

Enter fullscreen mode Exit fullscreen mode

5. ODT (OpenDocument Text) Generation

Using the odf-report gem you can create ODT files:


require 'odf-report'

class OdtGenerator
  def initialize(prd_json)
    @prd_json = prd_json
  end

  def generate_odt(output_path)
    report = ODFReport::Report.new("template.odt") do |r|
      r.add_field("TITLE", @prd_json['title'])
      @prd_json['sections'].each_with_index do |section, index|
        r.add_field("HEADING#{index+1}", section['heading'])
        r.add_field("CONTENT#{index+1}", section['content'])
      end
    end

    report.generate(output_path)
  end
end

Enter fullscreen mode Exit fullscreen mode

6. PDF Generation

Use prawn or wicked_pdf gems for PDF generation:


require 'prawn'

class PdfGenerator
  def initialize(prd_json)
    @prd_json = prd_json
  end

  def generate_pdf(output_path)
    Prawn::Document.generate(output_path) do |pdf|
      pdf.text @prd_json['title'], size: 24, style: :bold
      @prd_json['sections'].each do |section|
        pdf.move_down 10
        pdf.text section['heading'], size: 18, style: :bold
        pdf.text section['content'], size: 12
      end
    end
  end
end

Enter fullscreen mode Exit fullscreen mode

7. Plain Text (TXT) Export


class TxtGenerator
  def initialize(prd_json)
    @prd_json = prd_json
  end

  def generate_txt(output_path)
    content = []
    content << @prd_json['title']
    @prd_json['sections'].each do |section|
      content << "\n#{section['heading']}\n"
      content << "#{section['content']}\n"
    end
    File.write(output_path, content.join("\n"))
  end
end

Enter fullscreen mode Exit fullscreen mode

Why Build This in Rails?

  • Maintainability: Rails’ MVC and service object pattern cleanly separate concerns.
  • Extensibility: Easily add support for new formats (e.g., PDF, ODT).
  • Integration: Use ActiveJob and background processing for async generation.
  • Rich Ecosystem: Gems for document templating and HTTP clients simplify tasks.

Wrapping Up

By combining OpenAI’s powerful conversational models with Ruby on Rails’ flexible architecture , you can create robust pipelines that convert user conversations into well-structured documents automatically—saving time and reducing manual work.

Article content

Top comments (0)