Ruby

by appwriteab3c90b37c95No license10 starsListed Oct 8, 2026Updated Oct 8, 2026Repository updated 7 weeks ago

Appwrite Ruby SDK skill. Use when building server-side Ruby applications with Appwrite, including Rails and Sinatra integrations. Covers user management, database/table CRUD, file storage, and functions via API keys.

Instructions onlySoftware Development
AI-generated overview

Guides building server-side Ruby applications with the Appwrite SDK, covering users, databases, storage, teams, functions and SSR auth.

What it does
This skill provides reference instructions and code examples for using the Appwrite Ruby SDK in server-side applications, including Rails and Sinatra. It shows client setup with endpoint, project and API key, user management, table and row CRUD with query methods, file storage, teams and memberships, serverless function execution and handlers, SSR session authentication, error handling, and permission and role configuration. It produces guidance and snippets rather than runnable scripts.
When to use it
Use it when writing or reviewing Ruby server-side code that talks to Appwrite, such as setting up a client, performing database or storage operations, or implementing session-based authentication in a Rails or Sinatra app. It is also relevant when configuring Appwrite permissions and roles or handling SDK errors.
Requirements
Requires the appwrite Ruby gem and an Appwrite project with an endpoint, project ID and API key; network access to the Appwrite API. It ships no scripts, only instructions and code examples.

Appwrite Ruby SDK

Installation

bash
gem install appwrite

Setting Up the Client

ruby
require 'appwrite'
include Appwrite
client = Client.new    .set_endpoint('https://<REGION>.cloud.appwrite.io/v1')    .set_project(ENV['APPWRITE_PROJECT_ID'])    .set_key(ENV['APPWRITE_API_KEY'])

Code Examples

User Management

ruby
users = Users.new(client)
# Create useruser = users.create(user_id: ID.unique, email: '[email protected]', password: 'password123', name: 'User Name')
# List userslist = users.list(queries: [Query.limit(25)])
# Get userfetched = users.get(user_id: '[USER_ID]')
# Delete userusers.delete(user_id: '[USER_ID]')

Database Operations

Note: Use TablesDB (not the deprecated Databases class) for all new code. Only use Databases if the existing codebase already relies on it or the user explicitly requests it.

Tip: Prefer keyword arguments (e.g., database_id: '...') for all SDK method calls. Only use positional arguments if the existing codebase already uses them or the user explicitly requests it.

ruby
tables_db = TablesDB.new(client)
# Create databasedb = tables_db.create(database_id: ID.unique, name: 'My Database')
# Create rowdoc = tables_db.create_row(    database_id: '[DATABASE_ID]',    table_id: '[TABLE_ID]',    row_id: ID.unique,    data: { title: 'Hello World' })
# Query rowsresults = tables_db.list_rows(    database_id: '[DATABASE_ID]',    table_id: '[TABLE_ID]',    queries: [Query.equal('title', 'Hello World'), Query.limit(10)])
# Get rowrow = tables_db.get_row(database_id: '[DATABASE_ID]', table_id: '[TABLE_ID]', row_id: '[ROW_ID]')
# Update rowtables_db.update_row(    database_id: '[DATABASE_ID]',    table_id: '[TABLE_ID]',    row_id: '[ROW_ID]',    data: { title: 'Updated' })
# Delete rowtables_db.delete_row(database_id: '[DATABASE_ID]', table_id: '[TABLE_ID]', row_id: '[ROW_ID]')
String Column Types

Note: The legacy string type is deprecated. Use explicit column types for all new columns.

TypeMax charactersIndexingStorage
varchar16,383Full index (if size ≤ 768)Inline in row
text16,383Prefix onlyOff-page
mediumtext4,194,303Prefix onlyOff-page
longtext1,073,741,823Prefix onlyOff-page
  • varchar is stored inline and counts towards the 64 KB row size limit. Prefer for short, indexed fields like names, slugs, or identifiers.
  • text, mediumtext, and longtext are stored off-page (only a 20-byte pointer lives in the row), so they don't consume the row size budget. size is not required for these types.
ruby
# Create table with explicit string column typestables_db.create_table(    database_id: '[DATABASE_ID]',    table_id: ID.unique,    name: 'articles',    columns: [        { key: 'title',    type: 'varchar',    size: 255, required: true  },  # inline, fully indexable        { key: 'summary',  type: 'text',                  required: false },  # off-page, prefix index only        { key: 'body',     type: 'mediumtext',            required: false },  # up to ~4 M chars        { key: 'raw_data', type: 'longtext',              required: false },  # up to ~1 B chars    ])

Query Methods

ruby
# FilteringQuery.equal('field', 'value')             # == (or pass array for IN)Query.not_equal('field', 'value')         # !=Query.less_than('field', 100)             # <Query.less_than_equal('field', 100)       # <=Query.greater_than('field', 100)          # >Query.greater_than_equal('field', 100)    # >=Query.between('field', 1, 100)            # 1 <= field <= 100Query.is_null('field')                    # is nullQuery.is_not_null('field')                # is not nullQuery.starts_with('field', 'prefix')      # starts withQuery.ends_with('field', 'suffix')        # ends withQuery.contains('field', 'sub')            # containsQuery.search('field', 'keywords')         # full-text search (requires index)
# SortingQuery.order_asc('field')Query.order_desc('field')
# PaginationQuery.limit(25)                           # max rows (default 25, max 100)Query.offset(0)                           # skip N rowsQuery.cursor_after('[ROW_ID]')            # cursor pagination (preferred)Query.cursor_before('[ROW_ID]')
# Selection & LogicQuery.select(['field1', 'field2'])        # return only specified fieldsQuery.or([Query.equal('a', 1), Query.equal('b', 2)])   # ORQuery.and([Query.greater_than('age', 18), Query.less_than('age', 65)])  # AND (default)

File Storage

ruby
storage = Storage.new(client)
# Upload filefile = storage.create_file(bucket_id: '[BUCKET_ID]', file_id: ID.unique, file: InputFile.from_path('/path/to/file.png'))
# List filesfiles = storage.list_files(bucket_id: '[BUCKET_ID]')
# Delete filestorage.delete_file(bucket_id: '[BUCKET_ID]', file_id: '[FILE_ID]')
InputFile Factory Methods
ruby
InputFile.from_path('/path/to/file.png')             # from filesystem pathInputFile.from_string('Hello world', 'hello.txt')    # from string content

Teams

ruby
teams = Teams.new(client)
# Create teamteam = teams.create(team_id: ID.unique, name: 'Engineering')
# List teamslist = teams.list
# Create membership (invite user by email)membership = teams.create_membership(    team_id: '[TEAM_ID]',    roles: ['editor'],    email: '[email protected]')
# List membershipsmembers = teams.list_memberships(team_id: '[TEAM_ID]')
# Update membership rolesteams.update_membership(team_id: '[TEAM_ID]', membership_id: '[MEMBERSHIP_ID]', roles: ['admin'])
# Delete teamteams.delete(team_id: '[TEAM_ID]')

Role-based access: Use Role.team('[TEAM_ID]') for all team members or Role.team('[TEAM_ID]', 'editor') for a specific team role when setting permissions.

Serverless Functions

ruby
functions = Functions.new(client)
# Execute functionexecution = functions.create_execution(function_id: '[FUNCTION_ID]', body: '{"key": "value"}')
# List executionsexecutions = functions.list_executions(function_id: '[FUNCTION_ID]')
Writing a Function Handler (Ruby runtime)
ruby
# src/main.rb — Appwrite Function entry pointdef main(context)    # context.req.body         — raw body (String)    # context.req.body_json    — parsed JSON (Hash or nil)    # context.req.headers      — headers (Hash)    # context.req.method       — HTTP method    # context.req.path         — URL path    # context.req.query        — query params (Hash)
    context.log("Processing: #{context.req.method} #{context.req.path}")
    if context.req.method == 'GET'        return context.res.json({ message: 'Hello from Appwrite Function!' })    end
    context.res.json({ success: true })          # JSON    # context.res.text('Hello')                  # plain text    # context.res.empty                          # 204    # context.res.redirect('https://...')         # 302end

Server-Side Rendering (SSR) Authentication

SSR apps using Ruby frameworks (Rails, Sinatra, etc.) use the server SDK to handle auth. You need two clients:

  • Admin client — uses an API key, creates sessions, bypasses rate limits (reusable singleton)
  • Session client — uses a session cookie, acts on behalf of a user (create per-request, never share)
ruby
require 'appwrite'include Appwrite
# Admin client (reusable)admin_client = Client.new    .set_endpoint('https://<REGION>.cloud.appwrite.io/v1')    .set_project('[PROJECT_ID]')    .set_key(ENV['APPWRITE_API_KEY'])
# Session client (create per-request)session_client = Client.new    .set_endpoint('https://<REGION>.cloud.appwrite.io/v1')    .set_project('[PROJECT_ID]')
session = cookies['a_session_[PROJECT_ID]']session_client.set_session(session) if session
Email/Password Login (Sinatra)
ruby
post '/login' do    account = Account.new(admin_client)    session = account.create_email_password_session(        email: params[:email],        password: params[:password]    )
    # Cookie name must be a_session_<PROJECT_ID>    response.set_cookie('a_session_[PROJECT_ID]', {        value: session.secret,        httponly: true,        secure: true,        same_site: :strict,        path: '/',    })
    content_type :json    { success: true }.to_jsonend
Authenticated Requests
ruby
get '/user' do    session = request.cookies['a_session_[PROJECT_ID]']    halt 401, { error: 'Unauthorized' }.to_json unless session
    session_client = Client.new        .set_endpoint('https://<REGION>.cloud.appwrite.io/v1')        .set_project('[PROJECT_ID]')        .set_session(session)
    account = Account.new(session_client)    user = account.get
    content_type :json    user.to_jsonend
OAuth2 SSR Flow
ruby
# Step 1: Redirect to OAuth providerget '/oauth' do    account = Account.new(admin_client)    redirect_url = account.create_o_auth2_token(        provider: OAuthProvider::GITHUB,        success: 'https://example.com/oauth/success',        failure: 'https://example.com/oauth/failure'    )    redirect redirect_urlend
# Step 2: Handle callback — exchange token for sessionget '/oauth/success' do    account = Account.new(admin_client)    session = account.create_session(        user_id: params[:userId],        secret: params[:secret]    )
    response.set_cookie('a_session_[PROJECT_ID]', {        value: session.secret,        httponly: true, secure: true, same_site: :strict, path: '/',    })
    content_type :json    { success: true }.to_jsonend

Cookie security: Always use httponly, secure, and same_site: :strict to prevent XSS. The cookie name must be a_session_<PROJECT_ID>.

Forwarding user agent: Call session_client.set_forwarded_user_agent(request.user_agent) to record the end-user's browser info for debugging and security.

Error Handling

ruby
require 'appwrite'include Appwrite
begin    row = tables_db.get_row(database_id: '[DATABASE_ID]', table_id: '[TABLE_ID]', row_id: '[ROW_ID]')rescue Appwrite::Exception => e    puts e.message    # human-readable message    puts e.code       # HTTP status code (Integer)    puts e.type       # error type (e.g. 'document_not_found')    puts e.response   # full response body (Hash)end

Common error codes:

CodeMeaning
401Unauthorized — missing or invalid session/API key
403Forbidden — insufficient permissions
404Not found — resource does not exist
409Conflict — duplicate ID or unique constraint
429Rate limited — too many requests

Permissions & Roles (Critical)

Appwrite uses permission strings to control access to resources. Each permission pairs an action (read, update, delete, create, or write which grants create + update + delete) with a role target. By default, no user has access unless permissions are explicitly set at the row/file level or inherited from the table/bucket settings. Permissions are arrays of strings built with the Permission and Role helpers.

ruby
# Permission and Role are included in the main requirerequire 'appwrite'include Appwrite

Database Row with Permissions

ruby
doc = tables_db.create_row(    database_id: '[DATABASE_ID]',    table_id: '[TABLE_ID]',    row_id: ID.unique,    data: { title: 'Hello World' },    permissions: [        Permission.read(Role.user('[USER_ID]')),     # specific user can read        Permission.update(Role.user('[USER_ID]')),   # specific user can update        Permission.read(Role.team('[TEAM_ID]')),     # all team members can read        Permission.read(Role.any),                   # anyone (including guests) can read    ])

File Upload with Permissions

ruby
file = storage.create_file(    bucket_id: '[BUCKET_ID]',    file_id: ID.unique,    file: InputFile.from_path('/path/to/file.png'),    permissions: [        Permission.read(Role.any),        Permission.update(Role.user('[USER_ID]')),        Permission.delete(Role.user('[USER_ID]')),    ])

When to set permissions: Set row/file-level permissions when you need per-resource access control. If all rows in a table share the same rules, configure permissions at the table/bucket level and leave row permissions empty.

Common mistakes:

  • Forgetting permissions — the resource becomes inaccessible to all users (including the creator)
  • Role.any with write/update/delete — allows any user, including unauthenticated guests, to modify or remove the resource
  • Permission.read(Role.any) on sensitive data — makes the resource publicly readable

Source and attribution

Source:appwrite/claude-plugininskills/rubyat commitab3c90b

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal