Official SDK
Ruby
Ruby 2.7+ with Rails integration and idiomatic Ruby patterns. Clean API design with automatic retries and proper exception handling.
Rename PDFs, split multi-page documents, and extract structured data using the official Ruby SDK for Renamed.to.
- 1Add gem "renamed" to your Gemfile or run gem install renamed
- 2Call rename(), pdf_split(), or extract() with PDF bytes
- 3Integrate with Rails using the built-in generator and initializer
On this page
Installation
gem install renamedQuickstart
Initialize the client and start making API calls.
require 'renamed'# Initialize the clientclient = Renamed::Client.new(api_key: ENV['RENAMED_API_KEY'])# Rename a PDFresult = client.rename(File.read('invoice.pdf'))puts result.suggested_filename# -> "2024-01-15_AcmeCorp_INV-1234.pdf"# Split a multi-page PDFjob = client.pdf_split(File.read('documents.pdf'), mode: 'smart')puts job.documents# -> [{ filename: "...", download_url: "..." }, ...]# Extract structured datadata = client.extract(File.read('receipt.pdf'))puts data# -> { vendor: "...", date: "...", amount: "..." }Rename a PDF
Pass PDF bytes to get an AI-generated filename. Use custom instructions to control the naming format.
require 'renamed'# Initialize the clientclient = Renamed::Client.new(api_key: ENV['RENAMED_API_KEY'])# Read the PDF filepdf_bytes = File.binread('./documents/invoice.pdf')# Rename the PDFresult = client.rename(pdf_bytes)puts "Suggested filename: #{result.suggested_filename}"puts "Confidence: #{result.confidence}"# Output:# Suggested filename: 2024-01-15_AcmeCorp_INV-1234.pdf# Confidence: 0.95# Access extracted metadataputs "Vendor: #{result.metadata[:vendor]}"puts "Date: #{result.metadata[:date]}"puts "Type: #{result.metadata[:type]}"# Use custom naming instructionscustom_result = client.rename(pdf_bytes, instructions: 'Format: YYYY-MM-DD_VendorName_Amount')puts custom_result.suggested_filename# -> "2024-01-15_AcmeCorp_$1250.pdf"# Rename from a URLurl_result = client.rename_from_url('https://example.com/document.pdf')# Use a block for cleaner file handlingresult = File.open('./documents/invoice.pdf', 'rb') do |file| client.rename(file.read)endSplit a PDF
Split multi-page PDFs into separate documents. The API uses async jobs for large files—poll for completion or use the built-in wait helper.
require 'renamed'require 'fileutils'client = Renamed::Client.new(api_key: ENV['RENAMED_API_KEY'])# Read a multi-page PDFpdf_bytes = File.binread('./documents/combined.pdf')# Submit the split job with smart mode (AI detects document boundaries)job = client.pdf_split(pdf_bytes, mode: 'smart')puts "Job ID: #{job.job_id}"puts "Status: #{job.state}"# Option 1: Wait for completion (built-in polling)completed = job.wait_for_completion# Option 2: Manual polling for progress updates# while job.state == 'processing'# puts "Progress: #{job.progress}%"# sleep 1# job = client.get_job(job.job_id)# end# Process the split documentsputs "Split into #{completed.documents.length} documents:"completed.documents.each_with_index do |doc, i| puts " [#{i + 1}] #{doc.filename} (pages #{doc.pages.join(', ')})" # Output: # [1] invoice_1.pdf (pages 1, 2) # [2] invoice_2.pdf (pages 3, 4) # Download each split document doc_bytes = client.download_file(doc.download_url) # Save to output directory output_path = File.join('./output', doc.filename) FileUtils.mkdir_p(File.dirname(output_path)) File.binwrite(output_path, doc_bytes) puts " Saved: #{output_path}"end# With a timeoutcompleted = job.wait_for_completion(timeout: 300) # 5 minutesExtract Data
Extract structured data from invoices, receipts, and other documents. Use Ruby structs or classes for type-safe extraction.
require 'renamed'# Define typed structs for invoice extractionLineItem = Struct.new(:description, :quantity, :unit_price, keyword_init: true)Invoice = Struct.new( :invoice_number, :vendor, :date, :line_items, :subtotal, :tax, :total, keyword_init: true)# Initialize the clientclient = Renamed::Client.new(api_key: ENV['RENAMED_API_KEY'])# Read the PDF filepdf_bytes = File.binread('./documents/invoice.pdf')# Basic extraction (returns a Hash with symbol keys)data = client.extract(pdf_bytes)puts "Vendor: #{data[:vendor]}"puts "Date: #{data[:date]}"puts "Total: #{data[:total]}"# Output:# Vendor: Acme Corp# Date: 2024-01-15# Total: 1250.00# Typed extraction: convert to a structline_items = data[:line_items].map do |item| LineItem.new( description: item[:description], quantity: item[:quantity], unit_price: item[:unit_price] )endinvoice = Invoice.new( invoice_number: data[:invoice_number], vendor: data[:vendor], date: data[:date], line_items: line_items, subtotal: data[:subtotal], tax: data[:tax], total: data[:total])# Now you have typed accessputs "Invoice ##{invoice.invoice_number} from #{invoice.vendor}"puts "Line items: #{invoice.line_items.length}"invoice.line_items.each do |item| puts " - #{item.description}: #{item.quantity} x $#{'%.2f' % item.unit_price}"endputs "Total: $#{'%.2f' % invoice.total}"# Output:# Invoice #INV-2024-1234 from Acme Corp# Line items: 2# - Widget Pro: 5 x $199.00# - Support Plan: 1 x $342.50# Total: $1337.50Framework Integrations
Common integration patterns for popular frameworks.
Rails Controller
Handle PDF uploads in a Rails controller with proper error handling and response formatting.
# app/controllers/api/documents_controller.rbmodule Api class DocumentsController < ApplicationController before_action :validate_file, only: [:rename, :split, :extract] # POST /api/documents/rename def rename result = renamed_client.rename( file_param.read, instructions: params[:instructions] ) render json: { suggested_filename: result.suggested_filename, confidence: result.confidence, metadata: result.metadata } rescue Renamed::RateLimitError => e response.headers['Retry-After'] = e.retry_after.to_s render json: { error: 'Rate limited', retry_after: e.retry_after }, status: :too_many_requests rescue Renamed::ApiError => e render json: { error: e.message, code: e.code }, status: :bad_gateway end # POST /api/documents/split def split job = renamed_client.pdf_split( file_param.read, mode: params[:mode] || 'smart' ) completed = job.wait_for_completion render json: { job_id: completed.job_id, documents: completed.documents.map do |doc| { filename: doc.filename, pages: doc.pages, download_url: doc.download_url } end } rescue Renamed::ApiError => e render json: { error: e.message }, status: :bad_gateway end # POST /api/documents/extract def extract data = renamed_client.extract(file_param.read) render json: data rescue Renamed::ApiError => e render json: { error: e.message }, status: :bad_gateway end private def file_param params.require(:file) end def validate_file unless file_param.present? render json: { error: 'No file provided' }, status: :bad_request return end unless file_param.content_type == 'application/pdf' render json: { error: 'Only PDF files are supported' }, status: :bad_request return end end def renamed_client @renamed_client ||= Renamed::Client.new end endendRails Initializer
Configure the SDK globally in a Rails initializer with environment-based settings.
# config/initializers/renamed.rbRenamed.configure do |config| # API key from Rails credentials or environment config.api_key = Rails.application.credentials.dig(:renamed, :api_key) || ENV['RENAMED_API_KEY'] # Request timeout in seconds config.timeout = 30 # Number of automatic retries for transient errors config.max_retries = 3 # Custom logger (optional, defaults to Rails.logger in Rails apps) config.logger = Rails.logger # Base URL override (optional, for testing or custom endpoints) # config.base_url = 'https://api.renamed.to/v1'end# Verify configuration on startup (optional)Rails.application.config.after_initialize do unless Renamed.configuration.api_key.present? Rails.logger.warn '[Renamed] API key not configured!' endendActive Job Integration
Process PDF files asynchronously using Active Job for background processing.
# app/jobs/rename_document_job.rbclass RenameDocumentJob < ApplicationJob queue_as :documents retry_on Renamed::RateLimitError, wait: :polynomially_longer, attempts: 5 discard_on Renamed::InvalidFileError def perform(document_id) document = Document.find(document_id) # Download the file from storage pdf_bytes = document.file.download # Rename via the API result = Renamed::Client.new.rename( pdf_bytes, instructions: document.naming_instructions ) # Update the document record document.update!( suggested_filename: result.suggested_filename, confidence: result.confidence, metadata: result.metadata, processed_at: Time.current ) # Notify the user DocumentMailer.rename_complete(document).deliver_later rescue Renamed::ApiError => e document.update!( processing_error: e.message, processed_at: Time.current ) raise # Re-raise to trigger job retry endend# app/jobs/split_document_job.rbclass SplitDocumentJob < ApplicationJob queue_as :documents retry_on Renamed::RateLimitError, wait: :polynomially_longer, attempts: 5 def perform(document_id, mode: 'smart') document = Document.find(document_id) pdf_bytes = document.file.download # Start the split job job = Renamed::Client.new.pdf_split(pdf_bytes, mode: mode) # Poll for completion (job handles this internally) completed = job.wait_for_completion(timeout: 600) # 10 minutes # Create child documents for each split completed.documents.each do |doc| doc_bytes = Renamed::Client.new.download_file(doc.download_url) child = document.children.create!( filename: doc.filename, pages: doc.pages ) child.file.attach( io: StringIO.new(doc_bytes), filename: doc.filename, content_type: 'application/pdf' ) end document.update!( split_completed_at: Time.current, split_document_count: completed.documents.length ) endendError Handling
The SDK raises Ruby exceptions that you can rescue and handle appropriately. Use begin/rescue blocks for error handling.
require 'renamed'client = Renamed::Client.new(api_key: ENV['RENAMED_API_KEY'])begin pdf_bytes = File.binread('invoice.pdf') result = client.rename(pdf_bytes) puts "Renamed to: #{result.suggested_filename}"rescue Renamed::RateLimitError => e # Rate limited - wait and retry puts "Rate limited. Retry after #{e.retry_after} seconds" sleep e.retry_after # Retry the request...rescue Renamed::InvalidFileError => e # File is not a valid PDF or is corrupted puts "Invalid file: #{e.message}"rescue Renamed::AuthenticationError => e # API key is invalid or expired puts "Authentication failed: #{e.message}"rescue Renamed::ApiError => e # Other API errors puts "API Error [#{e.code}]: #{e.message}" puts "Details: #{e.details}" if e.detailsrescue Renamed::NetworkError => e # Network/connection errors puts "Network error: #{e.message}"rescue StandardError => e # Other errors (file I/O, etc.) puts "Unexpected error: #{e.message}"end# Using retry with exponential backoffdef rename_with_retry(client, pdf_bytes, max_retries: 3) retries = 0 begin client.rename(pdf_bytes) rescue Renamed::RateLimitError => e retries += 1 raise if retries > max_retries sleep_time = e.retry_after || (2 ** retries) puts "Rate limited, retrying in #{sleep_time}s (attempt #{retries}/#{max_retries})" sleep sleep_time retry rescue Renamed::ApiError => e retries += 1 raise if retries > max_retries || !e.retryable? sleep_time = 2 ** retries puts "API error, retrying in #{sleep_time}s (attempt #{retries}/#{max_retries})" sleep sleep_time retry endendFull documentation on GitHub
For more examples, advanced usage patterns, and detailed API documentation, see the full Ruby SDK README on GitHub.
Read the Ruby SDK docsFrequently asked questions
- What Ruby versions are supported?
- The Ruby SDK supports Ruby 2.7 and above. It works with both MRI Ruby and JRuby.
- Does it integrate with Rails?
- Yes, the SDK includes a Rails generator for easy configuration. Run rails g renamed:install to set up the initializer.
- How do I handle errors?
- The SDK raises Ruby exceptions that you can rescue. Specific error types include Renamed::RateLimitError and Renamed::APIError.
- Is the client thread-safe?
- Yes, the Renamed::Client is thread-safe. You can share a single instance across threads or create new instances as needed.
- Does it support file uploads from Active Storage?
- Yes, you can use document.file.download to get bytes from Active Storage and pass them to the SDK methods.