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

Ruby on Rails集成DocuSign:模板信封发送、预填及签收回传问题

问题描述

我正在开发一个基于Ruby on Rails的应用,通过授权码认证集成DocuSign,核心需求是:

  • 直接使用DocuSign平台上已包含文档的现有模板发送信封,无需从Rails应用附加额外文档
  • 预填模板中的字段值后,再发送给用户签署
  • 用户签署完成后,将已签署文档以PDF形式回传到Rails应用

当前进展

  • 已完成授权码认证的集成工作
  • 能通过现有模板创建并发送信封
  • 可获取未签署状态的PDF文件

遇到的问题

  • 移除附加文档的代码后,请求失败并返回document missing错误
  • 不清楚如何预填模板中的字段值
  • 不知道如何在用户签署完成后获取已签署的PDF文件

现有代码

def send_data_using_template(access_token)
    template_id = "8f33b649-****-4aa2-804a-01f2*****5e3"
    recipient_name = "ali676750"
    recipient_email = "abc@gmail.com"
    document_file_path = "config/Software licensing agreement.pdf"

    fields_to_prefill = {
      "name" => "ahmad",
      "title" => "software engineer"
    }
  
    signer1 = DocuSign_eSign::Signer.new(
      email: recipient_email,
      name: recipient_name,
      recipientId: '11',
      routing_order: '11'
    )
  
    document_base64 = Base64.strict_encode64(File.read(document_file_path))
    document = {
      documentBase64: document_base64,
      name: File.basename(document_file_path),
      fileExtension: File.extname(document_file_path).delete('.'),
      documentId: '1'
    }

    tabs = DocuSign_eSign::Tabs.new

    recipients = DocuSign_eSign::Recipients.new(
      signers: [signer1],
    )
    
    envelope_definition = DocuSign_eSign::EnvelopeDefinition.new(
        emailSubject: "Your subject line here",
      status: "sent",
      template_id: template_id,
      documents: [document],
      tabs: tabs
    )


    envelope_definition.recipients = recipients

    response = HTTParty.post("https://demo.docusign.net/restapi/v2.1/accounts/#{ENV['DOCUSIGN_ACCOUNT_ID']}/envelopes", 
                              headers: { "Authorization" => "Bearer #{access_token}", "Content-Type" => "application/json" },
                              body: envelope_definition.to_json)

    if response.code == 201
      puts "Envelope created successfully "
      envelope_id = response.parsed_response["envelopeId"]

      response = HTTParty.get(
        "https://demo.docusign.net/restapi/v2.1/accounts/#{ENV['DOCUSIGN_ACCOUNT_ID']}/envelopes/#{envelope_id}/documents/combined",
        headers: { "Authorization" => "Bearer #{access_token}" }
      )
      
      decoded_content = Base64.decode64(response.body)

      file_path = "config/signed_document.pdf"

      File.open(file_path, "wb") { |file| file.write(decoded_content) }

      puts "PDF file saved successfully at #{file_path}"
    else
      puts "Error creating envelope: #{response.body}"
    end
end

解决方案

1. 无需附加文档,直接使用模板发送信封

当使用现有模板创建信封时,不能同时指定template_id和documents参数,这会让DocuSign混淆文档来源,从而抛出document missing错误。只需要保留template_id,移除所有文档相关的代码即可。

修改后的核心代码片段:

# 移除所有文档读取、构造的代码
# document_base64 = Base64.strict_encode64(File.read(document_file_path))
# document = { ... }

# 创建信封定义时,仅保留必要参数
envelope_definition = DocuSign_eSign::EnvelopeDefinition.new(
  emailSubject: "Your subject line here",
  status: "sent",
  template_id: template_id
)

2. 预填模板中的字段值

预填字段需要通过TemplateRole关联签署人和模板中的角色,同时在Tabs中指定字段值(注意字段的tabLabel必须和模板中设置的完全一致)。

修改后的核心代码片段:

# 构造预填的文本字段,tabLabel必须和模板中定义的一致
text_tabs = [
  DocuSign_eSign::Text.new(
    tabLabel: "name",
    value: "ahmad"
  ),
  DocuSign_eSign::Text.new(
    tabLabel: "title",
    value: "software engineer"
  )
]

tabs = DocuSign_eSign::Tabs.new(text_tabs: text_tabs)

# 使用TemplateRole关联签署人和模板角色,roleName必须和模板中定义的角色名一致
template_role = DocuSign_eSign::TemplateRole.new(
  email: recipient_email,
  name: recipient_name,
  roleName: "Signer", # 替换为你模板中的角色名称
  tabs: tabs
)

# 将TemplateRole赋值给信封定义
envelope_definition.template_roles = [template_role]

3. 获取用户签署完成后的PDF

当前代码在信封创建成功后立即拉取文档,此时文档还未被签署。正确的做法是通过**DocuSign Webhook(Connect)**接收签署完成的通知,再拉取已签署的PDF,这是最高效的方式。

步骤1:配置Webhook

在DocuSign控制台中配置Connect:

  • 设置通知URL为你的Rails应用接口(比如/docusign/webhook)
  • 选择触发事件为Envelope Completed

步骤2:处理Webhook请求

在Rails中添加对应的控制器动作:

# routes.rb
post '/docusign/webhook', to: 'docusign#webhook'

# docusign_controller.rb
def webhook
  envelope_id = params[:envelopeId]
  status = params[:status]

  # 仅处理签署完成的事件
  if status == "completed"
    access_token = # 从你的token存储中获取有效access token
    response = HTTParty.get(
      "https://demo.docusign.net/restapi/v2.1/accounts/#{ENV['DOCUSIGN_ACCOUNT_ID']}/envelopes/#{envelope_id}/documents/combined",
      headers: { "Authorization" => "Bearer #{access_token}" }
    )

    if response.success?
      decoded_content = Base64.decode64(response.body)
      # 保存文件,建议用envelope_id命名避免重复
      file_path = "config/signed_document_#{envelope_id}.pdf"
      File.open(file_path, "wb") { |file| file.write(decoded_content) }
    end
  end

  # 必须返回200状态码给DocuSign,否则会重复发送通知
  head :ok
end

如果不想使用Webhook,也可以定时轮询信封状态,但Webhook是更优的方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 21:23:09