Protocol Buffers works smoothly with Ruby and is perfect for Rails APIs, microservices, and background jobs. While Ruby developers often use JSON, Protobuf offers faster serialization and smaller message sizes, especially useful when building mobile backends or high-performance services.
This guide shows you how to get started with Protocol Buffers in Ruby. We'll use simple examples and keep things practical. Ruby's clean syntax makes working with protobuf straightforward and enjoyable.
What You'll Need
- •Ruby: Version 2.7 or higher (check with
ruby -v
) - •Bundler: Ruby gem manager (usually comes with Ruby)
- •Protocol Buffer Compiler: We'll install this next
Step 1: Install Protocol Buffers
First, install the protobuf compiler (protoc
). On macOS:
brew install protobuf
On Ubuntu/Debian:
sudo apt update sudo apt install protobuf-compiler # Verify installation protoc --version
Next, add the Ruby protobuf gem to your Gemfile:
# Gemfile gem 'google-protobuf'
Install it:
bundle install
Step 2: Set Up Your Project
Create a simple Ruby project structure:
mkdir ruby-protobuf-demo cd ruby-protobuf-demo bundle init bundle add google-protobuf mkdir protos mkdir lib/generated -p
This creates a basic Ruby project with folders for proto files and generated code.
Step 3: Create Your .proto File
Create protos/subscriber.proto
with a telecom subscriber example:
syntax = "proto3"; package telecom; // Mobile subscriber information message Subscriber { string msisdn = 1; // Mobile number string name = 2; // Subscriber name string email = 3; // Email address SubscriptionType type = 4; // Plan type bool active = 5; // Account status repeated string services = 6; // Active services } enum SubscriptionType { PREPAID = 0; POSTPAID = 1; CORPORATE = 2; }
Step 4: Compile the .proto File
Generate Ruby code from your proto file:
protoc --ruby_out=lib/generated --proto_path=protos protos/subscriber.proto
This creates lib/generated/subscriber_pb.rb
with the Ruby classes.
Step 5: Use Protocol Buffers in Ruby
Create example.rb
:
require 'google/protobuf' require_relative 'lib/generated/subscriber_pb' # Create a new subscriber subscriber = Telecom::Subscriber.new( msisdn: '+91-9876543210', name: 'Telecom Customer', email: 'customer@telecom.com', type: :POSTPAID, active: true, services: ['Voice', 'Data', '4G LTE'] ) puts "Created subscriber: #{subscriber.name}" puts "MSISDN: #{subscriber.msisdn}" puts "Type: #{subscriber.type}" # Serialize to binary binary_data = Telecom::Subscriber.encode(subscriber) puts "Serialized to #{binary_data.bytesize} bytes" # Deserialize from binary decoded = Telecom::Subscriber.decode(binary_data) puts "\nDeserialized subscriber: #{decoded.name}" puts "Email: #{decoded.email}" puts "Active: #{decoded.active}" # Access repeated fields puts "\nActive services:" decoded.services.each do |service| puts " - #{service}" end
Step 6: Run Your Application
Run the Ruby script:
ruby example.rb
You should see output like:
Created subscriber: Telecom Customer MSISDN: +91-9876543210 Type: POSTPAID Serialized to 68 bytes Deserialized subscriber: Telecom Customer Email: customer@telecom.com Active: true Active services: - Voice - Data - 4G LTE
Saving and Loading from Files
Save and load protobuf data:
require 'google/protobuf' require_relative 'lib/generated/subscriber_pb' # Create subscriber subscriber = Telecom::Subscriber.new( msisdn: '+91-9123456789', name: 'Network Admin', email: 'admin@telecom.com', type: :CORPORATE, active: true ) # Save to file File.open('subscriber.bin', 'wb') do |file| file.write(Telecom::Subscriber.encode(subscriber)) end puts "Saved to file" # Load from file binary_data = File.read('subscriber.bin') loaded = Telecom::Subscriber.decode(binary_data) puts "Loaded: #{loaded.name}" puts "MSISDN: #{loaded.msisdn}"
Convert Between JSON and Protobuf
Ruby protobuf supports JSON encoding and decoding:
require 'google/protobuf' require_relative 'lib/generated/subscriber_pb' # Create subscriber subscriber = Telecom::Subscriber.new( msisdn: '+91-9876543210', name: 'Mobile User', type: :PREPAID, active: true ) # Convert to JSON json_string = Telecom::Subscriber.encode_json(subscriber) puts "JSON output:" puts json_string # Parse from JSON json_data = '{ "msisdn": "+91-9111111111", "name": "New Subscriber", "type": "POSTPAID", "active": true }' new_subscriber = Telecom::Subscriber.decode_json(json_data) puts "\nParsed from JSON: #{new_subscriber.name}" puts "Type: #{new_subscriber.type}"
Using Protobuf with Rails
Here's how to use Protobuf in a Rails API controller:
# app/controllers/subscribers_controller.rb class SubscribersController < ApplicationController require_relative '../../lib/generated/subscriber_pb' def create # Accept JSON, convert to Protobuf subscriber = Telecom::Subscriber.new( msisdn: params[:msisdn], name: params[:name], email: params[:email], type: :POSTPAID, active: true ) # Save to database or process... # Return protobuf binary render body: Telecom::Subscriber.encode(subscriber), content_type: 'application/x-protobuf' end def show # Fetch subscriber from database subscriber = Telecom::Subscriber.new( msisdn: params[:id], name: 'Retrieved Subscriber', type: :PREPAID, active: true ) # Return as protobuf render body: Telecom::Subscriber.encode(subscriber), content_type: 'application/x-protobuf' end def parse # Receive protobuf binary in request binary_data = request.body.read subscriber = Telecom::Subscriber.decode(binary_data) # Process the subscriber render json: { name: subscriber.name, msisdn: subscriber.msisdn, type: subscriber.type.to_s } end end
Best Practices for Ruby
Use Symbols for Enums
In Ruby, protobuf enums work as symbols. Use :POSTPAID
instead of strings for enum values.
Handle Binary Data Properly
When reading/writing files, always use binary mode ('wb'
or'rb'
) to avoid encoding issues.
Keep Generated Files Separate
Store generated Ruby files in a dedicated directory and never edit them manually. They'll be overwritten on recompilation.
Use Class Methods
Use encode
anddecode
class methods for cleaner serialization code.
Common Issues
Issue: Cannot load generated file
Solution: Make sure you're using require_relative
with the correct path to your generated _pb.rb
file.
Issue: Encoding errors with binary data
Solution: Always use binary mode when reading/writing protobuf files. Use File.open('file.bin', 'wb')
for writing.
Issue: protoc command not found
Solution: Install the Protocol Buffer compiler using Homebrew on macOS (brew install protobuf
) or apt on Ubuntu.
Related Tools
Additional Resources
Official Documentation & References
- Official Ruby Protobuf Tutorial - Google's official Ruby guide
- Ruby Protobuf on GitHub - Source code and examples
- Protobuf on RubyGems - Ruby gem repository
Conclusion
Protocol Buffers fits naturally into Ruby's ecosystem. The Ruby gem provides a clean, idiomatic API that feels right at home in Ruby code. Whether you're building Rails APIs, Sinatra microservices, or background workers, protobuf offers solid performance benefits.
Start with these simple examples and gradually integrate protobuf into your Ruby applications. You'll notice the performance improvements especially when dealing with mobile clients or high-throughput services.