Ruby
Primate runs Ruby with WebAssembly compilation, strongly-typed validation, sessions, and server-side routing.
Setup
Install Ruby
First, install Ruby 4.0 or later from the official website.
Install Module
npm install @primate/ruby
Configure
import config from "primate/config";
import ruby from "@primate/ruby";
export default config({
modules: [ruby()],
});
Initialize Ruby
Create a Gemfile in your project root:
bundle initAdd the Primate Ruby dependency:
# Gemfile
source "https://rubygems.org"
gem "primate-run", "~> 0.6.2"Install dependencies to vendor/bundle (required for WASM):
bundle config set --local path 'vendor/bundle'
bundle installThis creates Gemfile and Gemfile.lock files that manage your Ruby
dependencies.
Routes
Create Ruby route handlers in routes using .rb files. Routes are
compiled to WebAssembly and run in the JavaScript runtime.
# routes/hello.rb
require 'primate/route'
Route.get do |request|
'Hello, world!'
end
HTTP Methods
All standard HTTP methods are supported:
require 'primate/route'
Route.get do |request|
'GET request'
end
Route.post do |request|
'POST request'
end
Route.put do |request|
'PUT request'
end
Route.delete do |request|
'DELETE request'
end
Request Handling
Query Parameters
Access query parameters through the query request bag:
# routes/query.rb
require 'primate/route'
Route.get do |request|
if request.query.has?('foo')
request.query.get('foo')
else
'foo missing'
end
end
Request Body
Handle different body types based on content:
JSON Body
# routes/json.rb
require 'primate/route'
Route.post do |request|
begin
request.body.json
rescue => e
{ error: e.message }
end
end
Form Fields
# routes/form.rb
require 'primate/route'
Route.post do |request|
begin
request.body.form
rescue => e
{ error: e.message }
end
end
Text Body
# routes/text.rb
require 'primate/route'
Route.post do |request|
request.body.text
end
Binary Data
# routes/blob.rb
require 'primate/route'
Route.post(content_type: "application/octet-stream") do |request|
blob = request.body.blob
{
"type" => blob.type,
"size" => blob.size,
"head" => blob.head(4),
}
end
File Uploads
Handle multipart file uploads:
# routes/upload.rb
require 'primate/route'
Route.post(content_type: "multipart/form-data") do |request|
multipart = request.body.multipart
begin
# Get form form
form = multipart.form
# Get uploaded files
files = multipart.files
# Process files
file_info = files.map do |file|
{
field: file.field, # form field name
name: file.filename, # original filename
type: file.content_type, # MIME type
size: file.size # file size in bytes
}
end
{
form: form,
files: file_info
}
rescue => e
{ error: e.message }
end
end
Responses
Plain Data
Return any Ruby object that can be JSON serialized:
Route.get do |request|
{ name: 'Donald' }
end
Route.get do |request|
'Hello, world!'
end
Route.get do |request|
[
{ name: 'Donald' },
{ name: 'Ryan' }
]
end
Views
Render views with props:
# routes/view.rb
require 'primate/route'
require 'primate/response'
Route.get do |request|
Response.view('index.html', hello: 'world')
endWith options:
require 'primate/route'
require 'primate/response'
Route.get do |request|
Response.view('index.html',
{ hello: 'world' },
{ partial: true }
)
end
Redirects
Redirect to another route:
# routes/redirect.rb
require 'primate/route'
require 'primate/response'
Route.get do |request|
Response.redirect('/redirected')
endWith custom status code:
Route.get do |request|
Response.redirect('/redirected', status: 301) # moved permanently
end
Error Responses
Return error responses:
# routes/error.rb
require 'primate/route'
require 'primate/response'
Route.get do |request|
Response.error
endWith custom error options:
Route.get do |request|
Response.error(body: 'Custom error message')
end
Sessions
Manage user sessions with the session module:
Session methods await database-backed JavaScript promises internally. Call them from route handlers as shown below; failed operations raise an error.
# routes/session.rb
require 'primate/route'
require 'primate/session'
Route.get do |request|
# Create a session
Session.create(foo: 'bar')
# Get session data
Session.get
end
Session Methods
Session.create(data)- creates a new session with dataSession.get- gets session data (raises if no session)Session.try- gets session data (returns nil if no session)Session.set(data)- updates session dataSession.destroy- destroys the sessionSession.exists?- checks if session existsSession.id- gets the session ID
Ruby Conventions
Primate Ruby follows standard Ruby conventions:
Method Names
- Use
snake_casefor method and variable names - Use
?suffix for boolean methods:has?,exists? - Use
!suffix for destructive methods (when applicable)
Hash Syntax
Use modern Ruby hash syntax with symbols:
# Preferred
{ name: 'John', age: 30 }
# Also valid
{ :name => 'John', :age => 30 }
String Literals
Use single quotes for plain strings, double quotes for interpolation:
# Plain strings
message = 'Hello, world!'
# String interpolation
greeting = "Hello, #{name}!"
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
| extension | string |
".rb" |
Associated file extension |
Example
import ruby from "@primate/ruby";
import config from "primate/config";
export default config({
modules: [
ruby({
// use `.ruby` as associated file extension
extension: ".ruby",
}),
],
});
Resources
The gem's canonical source is maintained in the Primate monorepo under
backends/ruby. This does not change the primate-run gem name or its Ruby
require paths.