appwrite-ruby
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAppwrite Ruby SDK
Appwrite Ruby SDK
Installation
安装
bash
gem install appwritebash
gem install appwriteSetting 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'])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)ruby
users = Users.new(client)Create user
Create user
user = users.create(user_id: ID.unique, email: 'user@example.com', password: 'password123', name: 'User Name')
user = users.create(user_id: ID.unique, email: 'user@example.com', password: 'password123', name: 'User Name')
List users
List users
list = users.list(queries: [Query.limit(25)])
list = users.list(queries: [Query.limit(25)])
Get user
Get user
fetched = users.get(user_id: '[USER_ID]')
fetched = users.get(user_id: '[USER_ID]')
Delete user
Delete user
users.delete(user_id: '[USER_ID]')
undefinedusers.delete(user_id: '[USER_ID]')
undefinedDatabase Operations
数据库操作
Note: Use(not the deprecatedTablesDBclass) for all new code. Only useDatabasesif the existing codebase already relies on it or the user explicitly requests it.DatabasesTip: Prefer keyword arguments (e.g.,) for all SDK method calls. Only use positional arguments if the existing codebase already uses them or the user explicitly requests it.database_id: '...'
ruby
tables_db = TablesDB.new(client)注意: 所有新代码请使用(而非已弃用的TablesDB类)。仅当现有代码库已依赖Databases或用户明确要求时才使用它。Databases提示: 所有SDK方法调用优先使用关键字参数(例如)。仅当现有代码库已使用位置参数或用户明确要求时才使用位置参数。database_id: '...'
ruby
tables_db = TablesDB.new(client)Create database
Create database
db = tables_db.create(database_id: ID.unique, name: 'My Database')
db = tables_db.create(database_id: ID.unique, name: 'My Database')
Create row
Create row
doc = tables_db.create_row(
database_id: '[DATABASE_ID]',
table_id: '[TABLE_ID]',
row_id: ID.unique,
data: { title: 'Hello World' }
)
doc = tables_db.create_row(
database_id: '[DATABASE_ID]',
table_id: '[TABLE_ID]',
row_id: ID.unique,
data: { title: 'Hello World' }
)
Query rows
Query rows
results = tables_db.list_rows(
database_id: '[DATABASE_ID]',
table_id: '[TABLE_ID]',
queries: [Query.equal('title', 'Hello World'), Query.limit(10)]
)
results = tables_db.list_rows(
database_id: '[DATABASE_ID]',
table_id: '[TABLE_ID]',
queries: [Query.equal('title', 'Hello World'), Query.limit(10)]
)
Get row
Get row
row = tables_db.get_row(database_id: '[DATABASE_ID]', table_id: '[TABLE_ID]', row_id: '[ROW_ID]')
row = tables_db.get_row(database_id: '[DATABASE_ID]', table_id: '[TABLE_ID]', row_id: '[ROW_ID]')
Update row
Update row
tables_db.update_row(
database_id: '[DATABASE_ID]',
table_id: '[TABLE_ID]',
row_id: '[ROW_ID]',
data: { title: 'Updated' }
)
tables_db.update_row(
database_id: '[DATABASE_ID]',
table_id: '[TABLE_ID]',
row_id: '[ROW_ID]',
data: { title: 'Updated' }
)
Delete row
Delete row
tables_db.delete_row(database_id: '[DATABASE_ID]', table_id: '[TABLE_ID]', row_id: '[ROW_ID]')
undefinedtables_db.delete_row(database_id: '[DATABASE_ID]', table_id: '[TABLE_ID]', row_id: '[ROW_ID]')
undefinedString Column Types
字符串列类型
Note: The legacytype is deprecated. Use explicit column types for all new columns.string
| Type | Max characters | Indexing | Storage |
|---|---|---|---|
| 16,383 | Full index (if size ≤ 768) | Inline in row |
| 16,383 | Prefix only | Off-page |
| 4,194,303 | Prefix only | Off-page |
| 1,073,741,823 | Prefix only | Off-page |
- is stored inline and counts towards the 64 KB row size limit. Prefer for short, indexed fields like names, slugs, or identifiers.
varchar - ,
text, andmediumtextare stored off-page (only a 20-byte pointer lives in the row), so they don't consume the row size budget.longtextis not required for these types.size
ruby
undefined注意: 旧版类型已被弃用。所有新列请使用明确的列类型。string
| 类型 | 最大字符数 | 索引方式 | 存储方式 |
|---|---|---|---|
| 16,383 | 全索引(若长度 ≤ 768) | 行内存储 |
| 16,383 | 仅前缀索引 | 页外存储 |
| 4,194,303 | 仅前缀索引 | 页外存储 |
| 1,073,741,823 | 仅前缀索引 | 页外存储 |
- 存储在行内,占用64KB行大小限制。优先用于短的、需要索引的字段,如名称、短链接或标识符。
varchar - 、
text和mediumtext存储在页外(行内仅保留20字节的指针),因此不会占用行大小配额。这些类型不需要指定longtext。size
ruby
undefinedCreate table with explicit string column types
Create table with explicit string column types
tables_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
]
)
undefinedtables_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
]
)
undefinedQuery Methods
查询方法
ruby
undefinedruby
undefinedFiltering
Filtering
Query.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 <= 100
Query.is_null('field') # is null
Query.is_not_null('field') # is not null
Query.starts_with('field', 'prefix') # starts with
Query.ends_with('field', 'suffix') # ends with
Query.contains('field', 'sub') # contains
Query.search('field', 'keywords') # full-text search (requires index)
Query.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 <= 100
Query.is_null('field') # is null
Query.is_not_null('field') # is not null
Query.starts_with('field', 'prefix') # starts with
Query.ends_with('field', 'suffix') # ends with
Query.contains('field', 'sub') # contains
Query.search('field', 'keywords') # full-text search (requires index)
Sorting
Sorting
Query.order_asc('field')
Query.order_desc('field')
Query.order_asc('field')
Query.order_desc('field')
Pagination
Pagination
Query.limit(25) # max rows (default 25, max 100)
Query.offset(0) # skip N rows
Query.cursor_after('[ROW_ID]') # cursor pagination (preferred)
Query.cursor_before('[ROW_ID]')
Query.limit(25) # max rows (default 25, max 100)
Query.offset(0) # skip N rows
Query.cursor_after('[ROW_ID]') # cursor pagination (preferred)
Query.cursor_before('[ROW_ID]')
Selection & Logic
Selection & Logic
Query.select(['field1', 'field2']) # return only specified fields
Query.or([Query.equal('a', 1), Query.equal('b', 2)]) # OR
Query.and([Query.greater_than('age', 18), Query.less_than('age', 65)]) # AND (default)
undefinedQuery.select(['field1', 'field2']) # return only specified fields
Query.or([Query.equal('a', 1), Query.equal('b', 2)]) # OR
Query.and([Query.greater_than('age', 18), Query.less_than('age', 65)]) # AND (default)
undefinedFile Storage
文件存储
ruby
storage = Storage.new(client)ruby
storage = Storage.new(client)Upload file
Upload file
file = storage.create_file(bucket_id: '[BUCKET_ID]', file_id: ID.unique, file: InputFile.from_path('/path/to/file.png'))
file = storage.create_file(bucket_id: '[BUCKET_ID]', file_id: ID.unique, file: InputFile.from_path('/path/to/file.png'))
List files
List files
files = storage.list_files(bucket_id: '[BUCKET_ID]')
files = storage.list_files(bucket_id: '[BUCKET_ID]')
Delete file
Delete file
storage.delete_file(bucket_id: '[BUCKET_ID]', file_id: '[FILE_ID]')
undefinedstorage.delete_file(bucket_id: '[BUCKET_ID]', file_id: '[FILE_ID]')
undefinedInputFile Factory Methods
InputFile工厂方法
ruby
InputFile.from_path('/path/to/file.png') # from filesystem path
InputFile.from_string('Hello world', 'hello.txt') # from string contentruby
InputFile.from_path('/path/to/file.png') # from filesystem path
InputFile.from_string('Hello world', 'hello.txt') # from string contentTeams
团队管理
ruby
teams = Teams.new(client)ruby
teams = Teams.new(client)Create team
Create team
team = teams.create(team_id: ID.unique, name: 'Engineering')
team = teams.create(team_id: ID.unique, name: 'Engineering')
List teams
List teams
list = teams.list
list = teams.list
Create membership (invite user by email)
Create membership (invite user by email)
membership = teams.create_membership(
team_id: '[TEAM_ID]',
roles: ['editor'],
email: 'user@example.com'
)
membership = teams.create_membership(
team_id: '[TEAM_ID]',
roles: ['editor'],
email: 'user@example.com'
)
List memberships
List memberships
members = teams.list_memberships(team_id: '[TEAM_ID]')
members = teams.list_memberships(team_id: '[TEAM_ID]')
Update membership roles
Update membership roles
teams.update_membership(team_id: '[TEAM_ID]', membership_id: '[MEMBERSHIP_ID]', roles: ['admin'])
teams.update_membership(team_id: '[TEAM_ID]', membership_id: '[MEMBERSHIP_ID]', roles: ['admin'])
Delete team
Delete team
teams.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.teams.delete(team_id: '[TEAM_ID]')
> **基于角色的访问控制:** 设置权限时,使用`Role.team('[TEAM_ID]')`表示所有团队成员,或使用`Role.team('[TEAM_ID]', 'editor')`表示特定团队角色。Serverless Functions
无服务器函数
ruby
functions = Functions.new(client)ruby
functions = Functions.new(client)Execute function
Execute function
execution = functions.create_execution(function_id: '[FUNCTION_ID]', body: '{"key": "value"}')
execution = functions.create_execution(function_id: '[FUNCTION_ID]', body: '{"key": "value"}')
List executions
List executions
executions = functions.list_executions(function_id: '[FUNCTION_ID]')
undefinedexecutions = functions.list_executions(function_id: '[FUNCTION_ID]')
undefinedWriting a Function Handler (Ruby runtime)
编写函数处理器(Ruby运行时)
ruby
undefinedruby
undefinedsrc/main.rb — Appwrite Function entry point
src/main.rb — Appwrite Function entry point
def 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
undefineddef 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
undefinedServer-Side Rendering (SSR) Authentication
服务器端渲染(SSR)认证
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使用Ruby框架(Rails、Sinatra等)的SSR应用通过服务器SDK处理认证。你需要两个客户端:
- 管理员客户端 — 使用API密钥,可创建会话,绕过速率限制(可复用单例)
- 会话客户端 — 使用会话Cookie,代表用户执行操作(每个请求创建一次,切勿共享)
ruby
require 'appwrite'
include AppwriteAdmin client (reusable)
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'])
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 (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
undefinedsession_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
undefinedEmail/Password Login (Sinatra)
邮箱/密码登录(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_json
endruby
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_json
endAuthenticated 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_json
endruby
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_json
endOAuth2 SSR Flow
OAuth2 SSR流程
ruby
undefinedruby
undefinedStep 1: Redirect to OAuth provider
Step 1: Redirect to OAuth provider
get '/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_url
end
get '/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_url
end
Step 2: Handle callback — exchange token for session
Step 2: Handle callback — exchange token for session
get '/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.get '/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安全:** 始终使用`httponly`、`secure`和`same_site: :strict`以防止XSS攻击。Cookie名称必须为`a_session_<PROJECT_ID>`。
> **转发用户代理:** 调用`session_client.set_forwarded_user_agent(request.user_agent)`以记录终端用户的浏览器信息,用于调试和安全目的。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)
endCommon error codes:
| Code | Meaning |
|---|---|
| Unauthorized — missing or invalid session/API key |
| Forbidden — insufficient permissions |
| Not found — resource does not exist |
| Conflict — duplicate ID or unique constraint |
| Rate limited — too many requests |
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常见错误码:
| 状态码 | 含义 |
|---|---|
| 未授权 — 缺少或无效的会话/API密钥 |
| 禁止访问 — 权限不足 |
| 未找到 — 资源不存在 |
| 冲突 — 重复ID或唯一约束冲突 |
| 请求超限 — 请求次数过多 |
Permissions & Roles (Critical)
权限与角色(重点)
Appwrite uses permission strings to control access to resources. Each permission pairs an action (, , , , or which grants create + update + delete) with a role target. By default, no user has access unless permissions are explicitly set at the document/file level or inherited from the collection/bucket settings. Permissions are arrays of strings built with the and helpers.
readupdatedeletecreatewritePermissionRoleruby
undefinedAppwrite使用权限字符串控制资源访问。每个权限将操作(、、、,或包含create+update+delete的)与角色目标配对。默认情况下,所有用户都无访问权限,除非在文档/文件级别明确设置权限,或从集合/存储桶设置继承权限。权限是使用和助手构建的字符串数组。
readupdatedeletecreatewritePermissionRoleruby
undefinedPermission and Role are included in the main require
Permission and Role are included in the main require
require 'appwrite'
include Appwrite
undefinedrequire 'appwrite'
include Appwrite
undefinedDatabase 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
]
)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 document/file-level permissions when you need per-resource access control. If all documents in a collection share the same rules, configure permissions at the collection/bucket level and leave document permissions empty.
Common mistakes:
- Forgetting permissions — the resource becomes inaccessible to all users (including the creator)
withRole.any/write/update— allows any user, including unauthenticated guests, to modify or remove the resourcedelete on sensitive data — makes the resource publicly readablePermission.read(Role.any)
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]')),
]
)何时设置权限: 当需要按资源进行访问控制时,设置文档/文件级权限。如果集合中的所有文档共享相同规则,请在集合/存储桶级别配置权限,而文档权限留空。
常见错误:
- 忘记设置权限 — 资源对所有用户(包括创建者)都不可访问
- 对
/write/update使用delete— 允许任何用户(包括未认证访客)修改或删除资源Role.any- 对敏感数据使用
— 使资源可公开读取Permission.read(Role.any)