用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/kemalcr/kemal --skill kemal-view命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
Use when building, reviewing, debugging, testing, securing, or deploying web applications and HTTP APIs with the Kemal framework for Crystal. Covers Kemal routing, params, context, routers, filters, middleware, ECR, WebSockets, SSE, uploads, configuration, testing, and production concerns.
User authentication and session management in Kemal, following established project patterns.
Core Kemal development (routing verbs, parameters, modular router, version gates, response helpers).
| name | kemal-view |
| description | Rendering ECR templates and layouts with Kemal. |
| license | MIT |
This skill provides expert guidance on rendering HTML templates using ECR (Embedded Crystal) in Kemal, strictly following patterns from kemal-by-example.
render "path/to/view.ecr" for simple rendering.render "path/to/view.ecr", "path/to/layout.ecr" for layout support.src/views/index.ecr).HTML.escape(...) (require "html") when outputting with <%= ... %>.# blog/src/routes/posts.cr
get "/posts" do
posts = Post.all
render "src/views/posts/index.ecr", "src/views/layouts/application.ecr"
end
# ecommerce/src/routes/auth.cr
get "/signup" do |env|
current_user = Ecommerce::Auth.current_user(env)
cart_count = if (user = current_user) && (uid = user.id)
CartItem.total_quantity_for_user(uid)
else
0_i64
end
error_message = nil
render "src/views/auth/signup.ecr", "src/views/layouts/application.ecr"
end
# blog/src/routes/posts.cr
get "/posts/:id/edit" do |env|
id = env.params.url["id"]?.try(&.to_i64?)
post = id ? Post.find(id) : nil
if post
render "src/views/posts/edit.ecr", "src/views/layouts/application.ecr"
else
env.response.status = :not_found
"Post not found"
end
end
Typical layout file at src/views/layouts/application.ecr:
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
</head>
<body>
<nav>
<!-- Navigation content -->
</nav>
<main>
<%= content %>
</main>
<footer>
<!-- Footer content -->
</footer>
</body>
</html>
Typical view file at src/views/posts/index.ecr. ECR does not auto-escape output, so any user-provided value rendered with <%= ... %> must go through HTML.escape (stdlib, require "html") to prevent XSS:
<h1>Posts</h1>
<% posts.each do |post| %>
<article>
<h2><%= HTML.escape(post.title) %></h2>
<p><%= HTML.escape(post.body) %></p>
<a href="/posts/<%= post.id %>/edit">Edit</a>
</article>
<% end %>
<a href="/posts/new">New Post</a>
# ecommerce/src/routes/auth.cr
post "/login" do |env|
email = env.params.body["email"]?.try(&.strip) || ""
password = env.params.body["password"]?.try(&.strip) || ""
user = User.authenticate(email, password)
if user
Ecommerce::Auth.sign_in(env, user)
env.redirect "/products"
else
current_user = nil
cart_count = 0_i64
error_message = "Invalid email or password."
env.response.status = :unprocessable_entity
render "src/views/auth/login.ecr", "src/views/layouts/application.ecr"
end
end
<%= content %> in layout files to render the view content.render "path/to/_partial.ecr" for reusable UI components (not shown in examples but standard practice).<%= ... %> for output and <% ... %> for logic/control flow.HTML.escape(...) inside <%= ... %>; only render raw HTML you generated yourself (like the layout's <%= content %>).render.