Adding Electronic Signatures to a Rails 8 App


Integrating an electronic signature feature can be a great addition when building applications that require document signing. In this tutorial, we will walk through how to add a signature pad to a Rails 8 app using Tailwind CSS, PostgreSQL, and Importmap. We’ll leverage the signature_pad JavaScript library to enable users to draw their signatures directly within a form.



Step 1: Install Signature Pad

Rails 8 with Importmap allows us to pin JavaScript libraries easily. Start by running the following command to install signature_pad:

bin/importmap pin signature_pad
Enter fullscreen mode

Exit fullscreen mode

This command will pin signature_pad and update the importmap.rb file with:

pin "signature_pad" # @5.0.4
Enter fullscreen mode

Exit fullscreen mode



Step 2: Create a Stimulus Controller

Next, we will create a Stimulus controller to handle the signature pad interactions. Run the following command:

bin/rails generate stimulus signature_pad
Enter fullscreen mode

Exit fullscreen mode

Now, open the generated signature_pad_controller.js file and replace its contents with:

import  Controller  from "@hotwired/stimulus";
import SignaturePad from "signature_pad";

export default class extends Controller 
    static targets = ["canvas", "input"];

    connect() 
      this.signaturePad = new SignaturePad(
        this.canvasTarget,
         dotSize: 3, minWidth: 1, maxWidth: 3 
      );
      console.log("Please add signature before saving.");
    

    disconnect() 
      this.signaturePad.off();
    

    clear() 
      this.signaturePad.clear();
    

    submit(event) 
      event.preventDefault();

      this.canvasTarget.toBlob((blob) => 
        const signatureFile = new File([blob], "signature.png",  type: "image/png" );
        const dataTransfer = new DataTransfer();

        dataTransfer.items.add(signatureFile);
        this.inputTarget.files = dataTransfer.files;

        event.target.submit();
      );
    

Enter fullscreen mode

Exit fullscreen mode



Explanation of the Stimulus Controller

  • static targets = ["canvas", "input"]: Defines the elements our controller interacts with.
  • connect(): Initializes signature_pad on the canvas element.
  • disconnect(): Cleans up the signature pad instance when the controller is removed.
  • clear(): Clears the signature from the canvas when the clear button is clicked.
  • submit(event):

    • Prevents the default form submission.
    • Converts the signature drawn on the canvas to a blob.
    • Creates a File object and adds it to a DataTransfer instance.
    • Assigns the file to the hidden input field so it gets submitted with the form.



Step 3: Set Up the Model

To start, letโ€™s assume we have a Consent model. We will now add an attached signature:

class Consent < ApplicationRecord
  belongs_to :employee

  has_one_attached :signature #Add this line

  validates :first_name, :last_name, :phone_number, :email, :date_signed, presence: true
  validates :accepted, inclusion:  in: [ true ], message: "must be accepted" 
  validates :advisor_authorization, :consent_persistence, :information_confirmation, inclusion:  in: [ true ], message: "must be checked" 
end
Enter fullscreen mode

Exit fullscreen mode



Step 4: Update the Form

Now, let’s update the consent form to include the signature pad:

<%= form_for @consent, url: wizard_path, method: :put, class: "space-y-6 mb-12", data:  controller: "signature-pad", action: "submit->signature-pad#submit"  do |form| %>

  <div>
    <%= form.label :signature, class: "block text-sm font-normal text-slate-700 mt-8 mb-2" do %>
      Client Signature <span class="text-purple-500">*</span>
    <% end %>
    <% if consent.persisted? && consent.signature.attached? %>
      <%= image_tag consent.signature, class: "max-w-[300px] rounded border border-gray-300 mb-2" %>
    <% end %>
    <%= form.file_field :signature, data:  signature_pad_target: "input" , accept: "image/png", hidden: true %>
    <%= tag.canvas width: 950, height: 150, data:  signature_pad_target: "canvas" , class: "rounded-lg border border-gray-300 mb-2 hover:bg-gray-50 cursor-pointer" %>
    <%= tag.div class: "flex justify-between" do %>
      <%= tag.button "Clear", type: "button", data:  action: "signature-pad#clear" , class: "bg-gray-200 hover:bg-gray-300 text-gray-500 px-2 py-1 rounded" %>
    <% end %>
  </div>

  <div class="w-1/2 mt-2">
    <%= form.label :date_signed, class: "block text-sm font-normal text-slate-700" do %>
      Date signed <span class="text-purple-500">*</span>
    <% end %>
    <div class="mt-1">
      <%= form.date_field :date_signed, class: "block w-full rounded-lg border-slate-200 shadow-sm focus:border-purple-500 focus:ring-purple-500 sm:text-sm" %>
      <% if consent.errors[:date_signed].any? %>
        <p class="mt-2 text-sm text-red-600"><%= consent.errors[:date_signed].join(", ") %></p>
      <% end %>
    </div>
  </div>

  <div class="flex justify-between mt-16">
    <%= link_to "Go back", previous_wizard_path, class: "px-4 py-2 text-sm font-medium text-gray-700 border border-gray-300 rounded-md hover:bg-gray-100" %>
    <%= form.submit "Next step", class: "px-6 py-2 text-sm font-medium text-white bg-purple-500 rounded-md hover:bg-purple-600 focus:outline-none focus:ring focus:ring-purple-300 cursor-pointer" %>
  </div>
<% end %>
Enter fullscreen mode

Exit fullscreen mode



How the Form Uses the Stimulus Controller

  • data: controller: "signature-pad", action: "submit->signature-pad#submit" : Attaches the Stimulus controller to the form and links the submit action to the submit method in the controller.
  • Canvas Element (data: signature_pad_target: "canvas" ): This allows the controller to find the canvas for drawing signatures.
  • Hidden File Input (data: signature_pad_target: "input" ): Stores the converted signature as an image file for form submission.



Step 5: Testing the Signature Pad

Start your Rails server:

bin/rails server
Enter fullscreen mode

Exit fullscreen mode

signature

Gif signature

Navigate to your form page and test drawing a signature. When you submit, the signature should be stored as an attached file in your database.



Conclusion

In this tutorial, we integrated signature_pad into a Rails 8 application using Stimulus, Tailwind CSS, and PostgreSQL. We built a consent form where users can draw their signatures, store them in Active Storage, and submit them as part of their agreement. This approach can be extended to any document signing feature in a Rails app!

Happy coding! ๐Ÿš€



Source link