@tutorialkit-rb/cli 0.1.5 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +47 -38
- package/package.json +1 -1
- package/template/.claude/skills/rails-file-management/SKILL.md +211 -0
- package/template/.claude/skills/rails-lesson-recipes/SKILL.md +415 -0
- package/template/.claude/skills/rails-wasm-author-constraints/SKILL.md +181 -0
- package/template/.claude/skills/tutorial-content-structure/SKILL.md +377 -0
- package/template/.claude/skills/tutorial-lesson-config/SKILL.md +389 -0
- package/template/.claude/skills/tutorial-quickstart/SKILL.md +440 -0
- package/template/.github/workflows/deploy.yml +85 -0
- package/template/.gitignore +10 -0
- package/template/CLAUDE.md +47 -0
- package/template/astro.config.ts +12 -0
- package/template/bin/build-pack +84 -0
- package/template/bin/build-ruby-base +180 -0
- package/template/bin/link-local +13 -0
- package/template/bin/unlink-local +7 -0
- package/template/cors-proxy/README.md +63 -0
- package/template/cors-proxy/package-lock.json +1504 -0
- package/template/cors-proxy/package.json +12 -0
- package/template/cors-proxy/src/index.ts +87 -0
- package/template/cors-proxy/wrangler.toml +7 -0
- package/template/netlify.toml +9 -0
- package/template/package.json +12 -4
- package/template/ruby-wasm/Gemfile +6 -0
- package/template/ruby-wasm/Gemfile.base +19 -0
- package/template/ruby-wasm/Gemfile.base.lock +50 -0
- package/template/ruby-wasm/Gemfile.lock +8 -0
- package/template/ruby-wasm/bin/pack-gems +368 -0
- package/template/ruby-wasm/package.json +6 -0
- package/template/src/components/FileManager.tsx +33 -0
- package/template/src/components/HeadTags.astro +6 -6
- package/template/src/components/HelpDropdown.tsx +1 -1
- package/template/src/components/RailsPathLinkHandler.tsx +2 -2
- package/template/src/components/ShellConfigurator.tsx +6 -1
- package/template/src/content/tutorial/1-getting-started/1-creating-your-first-rails-app/content.md +4 -4
- package/template/src/content/tutorial/1-getting-started/2-rails-console/content.md +4 -4
- package/template/src/content/tutorial/2-controllers/2-crud-operations/content.md +2 -2
- package/template/src/content/tutorial/9-outbound-http/1-making-http-requests/_files/.tk-config.json +3 -0
- package/template/src/content/tutorial/9-outbound-http/1-making-http-requests/_files/workspace/app/controllers/http_demo_controller.rb +65 -0
- package/template/src/content/tutorial/9-outbound-http/1-making-http-requests/_files/workspace/app/views/http_demo/index.html.erb +172 -0
- package/template/src/content/tutorial/9-outbound-http/1-making-http-requests/_files/workspace/config/routes.rb +8 -0
- package/template/src/content/tutorial/9-outbound-http/1-making-http-requests/content.md +97 -0
- package/template/src/content/tutorial/9-outbound-http/meta.md +4 -0
- package/template/src/content/tutorial/meta.md +5 -0
- package/template/src/middleware.ts +14 -0
- package/template/src/templates/default/lib/boot-progress.js +49 -0
- package/template/src/templates/default/lib/http-bridge.js +55 -0
- package/template/src/templates/default/lib/patches/http_bridge.rb +167 -0
- package/template/src/templates/default/lib/rails.js +52 -5
- package/template/src/templates/default/lib/server.js +33 -1
- package/template/src/templates/default/package.json +4 -1
- package/template/src/templates/default/scripts/rails.js +1 -1
- package/template/src/templates/default/scripts/smoke-test.js +349 -0
- package/template/src/templates/default/scripts/wasi-loader.mjs +10 -0
- package/template/src/templates/default/workspace/_debug_app/.github/dependabot.yml +12 -0
- package/template/src/templates/default/workspace/_debug_app/.github/workflows/ci.yml +51 -0
- package/template/src/templates/default/workspace/_debug_app/.ruby-version +1 -0
- package/template/src/templates/default/workspace/_debug_app/Gemfile +37 -0
- package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/views/layouts/application.html.erb +1 -2
- package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/views/pwa/manifest.json.erb +2 -2
- package/template/src/templates/default/workspace/_debug_app/bin/dev +2 -0
- package/template/src/templates/default/workspace/_debug_app/bin/rake +4 -0
- package/template/src/templates/default/workspace/_debug_app/bin/setup +34 -0
- package/template/src/templates/default/workspace/_debug_app/config/application.rb +30 -0
- package/template/src/templates/default/workspace/_debug_app/config/cable.yml +10 -0
- package/template/src/templates/default/workspace/_debug_app/config/credentials.yml.enc +1 -0
- package/template/src/templates/default/workspace/_debug_app/config/master.key +1 -0
- package/template/src/templates/default/workspace/_debug_app/config/routes.rb +14 -0
- package/template/src/templates/default/workspace/_debug_app/test/models/.keep +0 -0
- package/template/src/templates/default/workspace/_debug_app/test/test_helper.rb +15 -0
- package/template/src/templates/default/workspace/_debug_app/tmp/.keep +0 -0
- package/template/src/templates/default/workspace/_debug_app/tmp/pids/.keep +0 -0
- package/template/src/templates/default/workspace/_debug_app/tmp/storage/.keep +0 -0
- package/template/src/templates/default/workspace/_debug_app/vendor/.keep +0 -0
- package/template/src/templates/rails-app/workspace/README.md +24 -0
- package/template/src/templates/rails-app/workspace/Rakefile +6 -0
- package/template/src/templates/rails-app/workspace/app/assets/images/.keep +0 -0
- package/template/src/templates/rails-app/workspace/app/assets/stylesheets/application.css +534 -0
- package/template/src/templates/rails-app/workspace/app/controllers/application_controller.rb +2 -0
- package/template/src/templates/rails-app/workspace/app/helpers/application_helper.rb +2 -0
- package/template/src/templates/rails-app/workspace/app/jobs/application_job.rb +7 -0
- package/template/src/templates/rails-app/workspace/app/mailers/application_mailer.rb +4 -0
- package/template/src/templates/rails-app/workspace/app/models/application_record.rb +3 -0
- package/template/src/templates/rails-app/workspace/app/models/concerns/.keep +0 -0
- package/template/src/templates/rails-app/workspace/app/views/layouts/application.html.erb +38 -0
- package/template/src/templates/rails-app/workspace/app/views/layouts/mailer.html.erb +13 -0
- package/template/src/templates/rails-app/workspace/app/views/layouts/mailer.text.erb +1 -0
- package/template/src/templates/rails-app/workspace/bin/rails +4 -0
- package/template/src/templates/rails-app/workspace/{store/config → config}/application.rb +1 -1
- package/template/src/templates/rails-app/workspace/config/boot.rb +3 -0
- package/template/src/templates/rails-app/workspace/config/database.yml +32 -0
- package/template/src/templates/rails-app/workspace/config/environment.rb +5 -0
- package/template/src/templates/rails-app/workspace/config/environments/development.rb +69 -0
- package/template/src/templates/rails-app/workspace/config/environments/production.rb +89 -0
- package/template/src/templates/rails-app/workspace/config/environments/test.rb +54 -0
- package/template/src/templates/rails-app/workspace/config/initializers/assets.rb +7 -0
- package/template/src/templates/rails-app/workspace/config/initializers/content_security_policy.rb +25 -0
- package/template/src/templates/rails-app/workspace/config/initializers/filter_parameter_logging.rb +8 -0
- package/template/src/templates/rails-app/workspace/config/initializers/inflections.rb +16 -0
- package/template/src/templates/rails-app/workspace/config/locales/en.yml +31 -0
- package/template/src/templates/rails-app/workspace/config/puma.rb +41 -0
- package/template/src/templates/rails-app/workspace/{store/config → config}/routes.rb +1 -1
- package/template/src/templates/rails-app/workspace/config/storage.yml +34 -0
- package/template/src/templates/rails-app/workspace/config.ru +6 -0
- package/template/src/templates/rails-app/workspace/db/seeds.rb +9 -0
- package/template/src/templates/rails-app/workspace/log/.keep +0 -0
- package/template/src/templates/rails-app/workspace/public/400.html +114 -0
- package/template/src/templates/rails-app/workspace/public/404.html +114 -0
- package/template/src/templates/rails-app/workspace/public/406-unsupported-browser.html +114 -0
- package/template/src/templates/rails-app/workspace/public/422.html +114 -0
- package/template/src/templates/rails-app/workspace/public/500.html +114 -0
- package/template/src/templates/rails-app/workspace/public/icon.png +0 -0
- package/template/src/templates/rails-app/workspace/public/icon.svg +3 -0
- package/template/src/templates/rails-app/workspace/public/robots.txt +1 -0
- package/template/src/templates/rails-app/workspace/script/.keep +0 -0
- package/template/src/templates/rails-app/workspace/storage/.keep +0 -0
- package/template/src/templates/rails-app/workspace/test/controllers/.keep +0 -0
- package/template/src/templates/rails-app/workspace/test/helpers/.keep +0 -0
- package/template/src/templates/rails-app/workspace/test/integration/.keep +0 -0
- package/template/src/templates/rails-app/workspace/tmp/.keep +0 -0
- package/template/src/templates/rails-app/workspace/tmp/cache/.keep +0 -0
- package/template/src/templates/rails-app/workspace/tmp/pids/.keep +0 -0
- package/template/src/templates/rails-app/workspace/tmp/sockets/.keep +0 -0
- package/template/src/templates/rails-app/workspace/tmp/storage/.keep +0 -0
- package/template/src/templates/rails-app/workspace/vendor/javascripts/.keep +0 -0
- package/template/tsconfig.json +3 -1
- package/template/uno.config.ts +17 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/README.md +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/Rakefile +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/assets/images/.keep +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/assets/stylesheets/application.css +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/controllers/application_controller.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store/app/models → default/workspace/_debug_app/app/controllers}/concerns/.keep +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/helpers/application_helper.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/jobs/application_job.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/mailers/application_mailer.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/models/application_record.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store/log → default/workspace/_debug_app/app/models/concerns}/.keep +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/views/layouts/mailer.html.erb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/views/layouts/mailer.text.erb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/app/views/pwa/service-worker.js +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/bin/rails +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/boot.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/database.yml +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/environment.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/environments/development.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/environments/production.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/environments/test.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/initializers/assets.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/initializers/content_security_policy.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/initializers/filter_parameter_logging.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/initializers/inflections.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/locales/en.yml +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/puma.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config/storage.yml +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/config.ru +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/db/seeds.rb +0 -0
- /package/template/src/templates/{rails-app/workspace/store/script → default/workspace/_debug_app/lib/tasks}/.keep +0 -0
- /package/template/src/templates/{rails-app/workspace/store/storage → default/workspace/_debug_app/log}/.keep +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/400.html +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/404.html +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/406-unsupported-browser.html +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/422.html +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/500.html +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/icon.png +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/icon.svg +0 -0
- /package/template/src/templates/{rails-app/workspace/store → default/workspace/_debug_app}/public/robots.txt +0 -0
- /package/template/src/templates/{rails-app/workspace/store/test/controllers → default/workspace/_debug_app/script}/.keep +0 -0
- /package/template/src/templates/{rails-app/workspace/store/test/helpers → default/workspace/_debug_app/storage}/.keep +0 -0
- /package/template/src/templates/{rails-app/workspace/store/test/integration → default/workspace/_debug_app/test/controllers}/.keep +0 -0
- /package/template/src/templates/{rails-app/workspace/store/tmp → default/workspace/_debug_app/test/fixtures/files}/.keep +0 -0
- /package/template/src/templates/{rails-app/workspace/store/tmp/pids → default/workspace/_debug_app/test/helpers}/.keep +0 -0
- /package/template/src/templates/{rails-app/workspace/store/tmp/storage → default/workspace/_debug_app/test/integration}/.keep +0 -0
- /package/template/src/templates/{rails-app/workspace/store/vendor/javascripts → default/workspace/_debug_app/test/mailers}/.keep +0 -0
- /package/template/src/templates/rails-app/workspace/{store/.ruby-version → .ruby-version} +0 -0
- /package/template/src/templates/rails-app/workspace/{store/Gemfile → Gemfile} +0 -0
- /package/template/src/templates/rails-app/workspace/{store/app → app}/javascript/application.js +0 -0
- /package/template/src/templates/rails-app/workspace/{store/app → app}/javascript/controllers/application.js +0 -0
- /package/template/src/templates/rails-app/workspace/{store/app → app}/javascript/controllers/index.js +0 -0
- /package/template/src/templates/rails-app/workspace/{store/bin → bin}/importmap +0 -0
- /package/template/src/templates/rails-app/workspace/{store/config → config}/cable.yml +0 -0
- /package/template/src/templates/rails-app/workspace/{store/config → config}/credentials.yml.enc +0 -0
- /package/template/src/templates/rails-app/workspace/{store/config → config}/importmap.rb +0 -0
- /package/template/src/templates/rails-app/workspace/{store/config → config}/master.key +0 -0
- /package/template/src/templates/rails-app/workspace/{store/test → test}/test_helper.rb +0 -0
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rails-lesson-recipes
|
|
3
|
+
description: |
|
|
4
|
+
Use this skill whenever creating a new lesson, choosing a lesson pattern, or validating
|
|
5
|
+
lesson structure. Trigger on: 'create a lesson', 'lesson recipe', 'lesson pattern',
|
|
6
|
+
'terminal-only lesson', 'code editing lesson', 'database lesson', 'console lesson',
|
|
7
|
+
'lesson sequence', 'multi-step lesson', 'validate lesson', 'check lesson', or asking
|
|
8
|
+
how to structure a Rails lesson — even without mentioning recipes. Provides five tested
|
|
9
|
+
blueprints (terminal-only, code-editing, database, full-app, console/IRB) with correct
|
|
10
|
+
frontmatter, directory layouts, content examples, and a post-creation validation
|
|
11
|
+
checklist. Do NOT create lessons without this skill — incorrect structure causes silent
|
|
12
|
+
failures. Do NOT use for frontmatter reference (use tutorial-lesson-config) or file
|
|
13
|
+
organization (use rails-file-management).
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Rails Lesson Recipes
|
|
17
|
+
|
|
18
|
+
Ready-to-use patterns for common Rails tutorial lesson types.
|
|
19
|
+
|
|
20
|
+
## Recipe 1: Terminal-Only Lesson
|
|
21
|
+
|
|
22
|
+
**Use for:** Running generators, using the console, exploring CLI tools.
|
|
23
|
+
**Example:** `rails new`, `rails console`, `rails generate`.
|
|
24
|
+
|
|
25
|
+
### Directory Structure
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
1-creating-your-first-rails-app/
|
|
29
|
+
content.md
|
|
30
|
+
_files/
|
|
31
|
+
workspace/
|
|
32
|
+
.keep
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Frontmatter
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
---
|
|
39
|
+
type: lesson
|
|
40
|
+
title: Creating your first Rails app
|
|
41
|
+
editor: false
|
|
42
|
+
custom:
|
|
43
|
+
shell:
|
|
44
|
+
workdir: "/workspace"
|
|
45
|
+
---
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Key Decisions
|
|
49
|
+
|
|
50
|
+
- `editor: false` — the user only interacts via terminal
|
|
51
|
+
- `previews: false` — inherited from tutorial root (no server running)
|
|
52
|
+
- Empty `workspace/.keep` — user creates the app from scratch
|
|
53
|
+
- `workdir: "/workspace"` — terminal starts at the workspace root (before app exists)
|
|
54
|
+
|
|
55
|
+
### Content Pattern
|
|
56
|
+
|
|
57
|
+
```markdown
|
|
58
|
+
# Creating Your First Rails App
|
|
59
|
+
|
|
60
|
+
Run the following command to generate a new Rails application:
|
|
61
|
+
|
|
62
|
+
\`\`\`bash
|
|
63
|
+
$ rails new store
|
|
64
|
+
\`\`\`
|
|
65
|
+
|
|
66
|
+
:::info
|
|
67
|
+
This may take a moment as Rails generates the application structure.
|
|
68
|
+
:::
|
|
69
|
+
|
|
70
|
+
After your new application is created, switch to its directory:
|
|
71
|
+
|
|
72
|
+
\`\`\`bash
|
|
73
|
+
$ cd store
|
|
74
|
+
\`\`\`
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Recipe 2: Code-Editing Lesson (with Preview)
|
|
80
|
+
|
|
81
|
+
**Use for:** Writing controllers, models, views, routes — any lesson where the user edits code and sees results.
|
|
82
|
+
**Example:** Adding a new action, modifying a view, updating routes.
|
|
83
|
+
|
|
84
|
+
### Directory Structure
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
3-adding-a-controller/
|
|
88
|
+
content.md
|
|
89
|
+
_files/
|
|
90
|
+
.tk-config.json
|
|
91
|
+
workspace/
|
|
92
|
+
app/
|
|
93
|
+
controllers/
|
|
94
|
+
pages_controller.rb ← starter/skeleton code
|
|
95
|
+
config/
|
|
96
|
+
routes.rb
|
|
97
|
+
_solution/
|
|
98
|
+
workspace/
|
|
99
|
+
app/
|
|
100
|
+
controllers/
|
|
101
|
+
pages_controller.rb ← completed code
|
|
102
|
+
views/
|
|
103
|
+
pages/
|
|
104
|
+
home.html.erb ← new file the user creates
|
|
105
|
+
config/
|
|
106
|
+
routes.rb
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Frontmatter
|
|
110
|
+
|
|
111
|
+
```yaml
|
|
112
|
+
---
|
|
113
|
+
type: lesson
|
|
114
|
+
title: Adding a Controller
|
|
115
|
+
focus: /workspace/app/controllers/pages_controller.rb
|
|
116
|
+
previews: [3000]
|
|
117
|
+
mainCommand: ['node scripts/rails.js server', 'Starting Rails server']
|
|
118
|
+
custom:
|
|
119
|
+
shell:
|
|
120
|
+
workdir: '/workspace'
|
|
121
|
+
---
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### `.tk-config.json`
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"extends": "../../../../../templates/rails-app"
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Key Decisions
|
|
133
|
+
|
|
134
|
+
- `focus` opens the file the user will edit
|
|
135
|
+
- `previews: [3000]` shows the Rails app in a preview pane
|
|
136
|
+
- `mainCommand` starts the Rails server after prepare commands finish
|
|
137
|
+
- `_solution/` includes both modified files and new files the user was asked to create
|
|
138
|
+
- Inherits `prepareCommands` (npm install) from tutorial root
|
|
139
|
+
|
|
140
|
+
### Content Pattern
|
|
141
|
+
|
|
142
|
+
```markdown
|
|
143
|
+
# Adding a Controller
|
|
144
|
+
|
|
145
|
+
Open `app/controllers/pages_controller.rb` in the editor. Add a `home` action:
|
|
146
|
+
|
|
147
|
+
\`\`\`ruby title="app/controllers/pages_controller.rb" ins={2-4}
|
|
148
|
+
class PagesController < ApplicationController
|
|
149
|
+
def home
|
|
150
|
+
@message = "Welcome to our store!"
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
\`\`\`
|
|
154
|
+
|
|
155
|
+
Now create the view at `app/views/pages/home.html.erb`:
|
|
156
|
+
|
|
157
|
+
\`\`\`erb title="app/views/pages/home.html.erb"
|
|
158
|
+
<h1><%= @message %></h1>
|
|
159
|
+
\`\`\`
|
|
160
|
+
|
|
161
|
+
:::tip
|
|
162
|
+
Click **Solve** to see the completed code if you get stuck.
|
|
163
|
+
:::
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Recipe 3: Database Lesson
|
|
169
|
+
|
|
170
|
+
**Use for:** Migrations, models, seeds, ActiveRecord queries.
|
|
171
|
+
**Example:** Creating a model, running migrations, seeding data.
|
|
172
|
+
|
|
173
|
+
### Directory Structure
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
1-creating-a-model/
|
|
177
|
+
content.md
|
|
178
|
+
_files/
|
|
179
|
+
.tk-config.json
|
|
180
|
+
workspace/
|
|
181
|
+
db/
|
|
182
|
+
migrate/
|
|
183
|
+
20240101000000_create_products.rb
|
|
184
|
+
seeds.rb
|
|
185
|
+
app/
|
|
186
|
+
models/
|
|
187
|
+
product.rb
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Frontmatter
|
|
191
|
+
|
|
192
|
+
```yaml
|
|
193
|
+
---
|
|
194
|
+
type: lesson
|
|
195
|
+
title: Creating a Product Model
|
|
196
|
+
focus: /workspace/app/models/product.rb
|
|
197
|
+
previews: [3000]
|
|
198
|
+
mainCommand: ['node scripts/rails.js server', 'Starting Rails server']
|
|
199
|
+
prepareCommands:
|
|
200
|
+
- ['npm install', 'Preparing Ruby runtime']
|
|
201
|
+
- ['node scripts/rails.js db:prepare', 'Prepare development database']
|
|
202
|
+
terminalBlockingPrepareCommandsCount: 2
|
|
203
|
+
custom:
|
|
204
|
+
shell:
|
|
205
|
+
workdir: '/workspace'
|
|
206
|
+
---
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Key Decisions
|
|
210
|
+
|
|
211
|
+
- `prepareCommands` includes `db:prepare` — this runs migrations and seeds **before** the lesson becomes interactive
|
|
212
|
+
- Migration files must have timestamps in filenames (Rails convention)
|
|
213
|
+
- Seeds provide starting data so the user sees something immediately
|
|
214
|
+
- Override `prepareCommands` at the lesson level (doesn't inherit the tutorial root's single command)
|
|
215
|
+
|
|
216
|
+
### Content Pattern
|
|
217
|
+
|
|
218
|
+
```markdown
|
|
219
|
+
# Creating a Product Model
|
|
220
|
+
|
|
221
|
+
Your Product model is defined in `app/models/product.rb`. Let's add validations:
|
|
222
|
+
|
|
223
|
+
\`\`\`ruby title="app/models/product.rb"
|
|
224
|
+
class Product < ApplicationRecord
|
|
225
|
+
validates :name, presence: true
|
|
226
|
+
validates :price, numericality: { greater_than: 0 }
|
|
227
|
+
end
|
|
228
|
+
\`\`\`
|
|
229
|
+
|
|
230
|
+
The migration has already been run. Try it in the console:
|
|
231
|
+
|
|
232
|
+
\`\`\`bash
|
|
233
|
+
$ bin/rails console
|
|
234
|
+
\`\`\`
|
|
235
|
+
|
|
236
|
+
\`\`\`irb
|
|
237
|
+
store(dev)> Product.create(name: "Widget", price: 9.99)
|
|
238
|
+
store(dev)> Product.all
|
|
239
|
+
\`\`\`
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Recipe 4: Full-App Lesson (Pre-Built State)
|
|
245
|
+
|
|
246
|
+
**Use for:** Teaching concepts that require a fully scaffolded app — CRUD, associations, authentication.
|
|
247
|
+
**Example:** CRUD operations on an existing scaffold.
|
|
248
|
+
|
|
249
|
+
### Directory Structure
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
2-crud-operations/
|
|
253
|
+
content.md
|
|
254
|
+
_files/
|
|
255
|
+
.tk-config.json
|
|
256
|
+
workspace/
|
|
257
|
+
.keep
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Frontmatter
|
|
261
|
+
|
|
262
|
+
```yaml
|
|
263
|
+
---
|
|
264
|
+
type: lesson
|
|
265
|
+
title: CRUD Operations
|
|
266
|
+
focus: /workspace/app/controllers/products_controller.rb
|
|
267
|
+
previews: [3000]
|
|
268
|
+
mainCommand: ['node scripts/rails.js server', 'Starting Rails server']
|
|
269
|
+
prepareCommands:
|
|
270
|
+
- ['npm install', 'Preparing Ruby runtime']
|
|
271
|
+
- ['node scripts/rails.js db:prepare', 'Prepare development database']
|
|
272
|
+
terminalBlockingPrepareCommandsCount: 2
|
|
273
|
+
custom:
|
|
274
|
+
shell:
|
|
275
|
+
workdir: '/workspace'
|
|
276
|
+
---
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### `.tk-config.json`
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
{
|
|
283
|
+
"extends": "../../../../../templates/crud-products"
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Key Decisions
|
|
288
|
+
|
|
289
|
+
- Uses `crud-products` template which provides a complete scaffolded app
|
|
290
|
+
- `_files/` only contains `.tk-config.json` and a `.keep` — the template provides everything
|
|
291
|
+
- `focus` points to the file being discussed in the lesson
|
|
292
|
+
- No `_solution/` needed — this is an exploration/explanation lesson, not a coding exercise
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Recipe 5: Console/IRB Lesson
|
|
297
|
+
|
|
298
|
+
**Use for:** Interactive Ruby exploration, testing models, querying the database.
|
|
299
|
+
|
|
300
|
+
### Directory Structure
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
2-rails-console/
|
|
304
|
+
content.md
|
|
305
|
+
_files/
|
|
306
|
+
.tk-config.json
|
|
307
|
+
workspace/
|
|
308
|
+
.keep
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Frontmatter
|
|
312
|
+
|
|
313
|
+
```yaml
|
|
314
|
+
---
|
|
315
|
+
type: lesson
|
|
316
|
+
title: Rails Console
|
|
317
|
+
custom:
|
|
318
|
+
shell:
|
|
319
|
+
workdir: "/workspace"
|
|
320
|
+
---
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Key Decisions
|
|
324
|
+
|
|
325
|
+
- No `editor`, no `previews`, no `mainCommand` — user works entirely in the terminal
|
|
326
|
+
- Inherits `editor: true` by default but doesn't need to set `editor: false` since the user can still browse files
|
|
327
|
+
- Uses a pre-built template via `.tk-config.json` so there's an app to explore
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Building Lesson Sequences
|
|
332
|
+
|
|
333
|
+
### Progressive State Pattern
|
|
334
|
+
|
|
335
|
+
For a series of lessons that build on each other, use **template layering**:
|
|
336
|
+
|
|
337
|
+
```
|
|
338
|
+
src/templates/
|
|
339
|
+
default/ ← Base WASM runtime
|
|
340
|
+
rails-app/ ← Empty Rails app (extends default)
|
|
341
|
+
blog-base/ ← Blog app with Post model (extends rails-app)
|
|
342
|
+
blog-with-comments/ ← Blog app + Comment model (extends blog-base)
|
|
343
|
+
|
|
344
|
+
src/content/tutorial/
|
|
345
|
+
1-blog/
|
|
346
|
+
meta.md ← type: part
|
|
347
|
+
1-setup/
|
|
348
|
+
content.md ← Uses rails-app template
|
|
349
|
+
_files/.tk-config.json → ../../../../../templates/rails-app
|
|
350
|
+
2-posts/
|
|
351
|
+
content.md ← Uses blog-base template
|
|
352
|
+
_files/.tk-config.json → ../../../../../templates/blog-base
|
|
353
|
+
3-comments/
|
|
354
|
+
content.md ← Uses blog-with-comments template
|
|
355
|
+
_files/.tk-config.json → ../../../../../templates/blog-with-comments
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Each template captures the **expected state** at the start of that lesson. This way:
|
|
359
|
+
- Users can jump to any lesson without completing previous ones
|
|
360
|
+
- Each lesson starts from a known-good state
|
|
361
|
+
- Template inheritance keeps file duplication minimal
|
|
362
|
+
|
|
363
|
+
### When to Create a New Template vs. Use `_files/`
|
|
364
|
+
|
|
365
|
+
| Create a Template | Use `_files/` |
|
|
366
|
+
|-------------------|---------------|
|
|
367
|
+
| State is reused by 3+ lessons | Only this lesson needs these files |
|
|
368
|
+
| State is complex (many files) | Just 1-3 files differ from the template |
|
|
369
|
+
| You want users to jump to this lesson directly | Sequential lessons where order matters |
|
|
370
|
+
|
|
371
|
+
### Lesson-to-Lesson Expectations
|
|
372
|
+
|
|
373
|
+
**Always assume each lesson starts fresh.** The WASM runtime reinstalls on lesson navigation. Design each lesson to be self-contained:
|
|
374
|
+
|
|
375
|
+
1. Use `prepareCommands` for setup (npm install, db:prepare) and `terminalBlockingPrepareCommandsCount: <number of commands>` to ensure terminal is not used before the prepare commands finish.
|
|
376
|
+
2. Use templates or `_files/` for starting code state
|
|
377
|
+
3. Don't rely on user actions from a previous lesson
|
|
378
|
+
|
|
379
|
+
## Post-Creation Checklist
|
|
380
|
+
|
|
381
|
+
After creating a lesson, verify these structural requirements. Violations cause silent failures at runtime.
|
|
382
|
+
|
|
383
|
+
### Required
|
|
384
|
+
|
|
385
|
+
- [ ] `content.md` exists in the lesson directory and has `type: lesson` in frontmatter
|
|
386
|
+
- [ ] `content.md` has a `title` in frontmatter
|
|
387
|
+
- [ ] All file paths in `_files/` start with `workspace/` (not `/workspace/`)
|
|
388
|
+
- [ ] All file paths in `_solution/` start with `workspace/` (not `/workspace/`)
|
|
389
|
+
- [ ] If `.tk-config.json` exists in `_files/`, its `extends` path resolves to an existing template directory under `src/templates/`
|
|
390
|
+
- [ ] `_solution/` mirrors the `_files/` directory structure (paths must match for "Solve" to replace correctly)
|
|
391
|
+
- [ ] `custom.shell.workdir` is set on the lesson itself (it does NOT inherit from parent `meta.md`)
|
|
392
|
+
|
|
393
|
+
### If previews are enabled
|
|
394
|
+
|
|
395
|
+
- [ ] `previews` is set (e.g., `previews: [3000]`)
|
|
396
|
+
- [ ] `mainCommand` is set to start the server (e.g., `['node scripts/rails.js server', 'Starting Rails server']`)
|
|
397
|
+
- [ ] `prepareCommands` includes `npm install` (either inherited from tutorial root or set explicitly)
|
|
398
|
+
|
|
399
|
+
### If database is used
|
|
400
|
+
|
|
401
|
+
- [ ] `prepareCommands` includes **both** `npm install` and `node scripts/rails.js db:prepare` (remember: arrays replace, not merge)
|
|
402
|
+
- [ ] Migration files have timestamp prefixes in filenames
|
|
403
|
+
- [ ] Seeds file exists if the lesson needs starting data
|
|
404
|
+
|
|
405
|
+
### If focus is set
|
|
406
|
+
|
|
407
|
+
- [ ] `focus` path is absolute from WebContainer root (e.g., `/workspace/app/...`)
|
|
408
|
+
- [ ] The file at `focus` path exists in `_files/` or in the referenced template
|
|
409
|
+
- [ ] `editor` is not set to `false` (focus is silently ignored when editor is hidden)
|
|
410
|
+
|
|
411
|
+
### Path verification
|
|
412
|
+
|
|
413
|
+
- [ ] `.tk-config.json` `extends` uses correct `../` count: 4 + number of intermediate levels above the lesson (typically 5 for `tutorial/part/lesson/_files/`)
|
|
414
|
+
- [ ] `focus` paths use `/workspace/...` (absolute), while `_files/` paths use `workspace/...` (relative, no leading slash)
|
|
415
|
+
- [ ] `scope` paths use `/workspace/...` (absolute)
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rails-wasm-author-constraints
|
|
3
|
+
description: |
|
|
4
|
+
Use this skill whenever checking if a Rails feature or gem works in WASM, or understanding
|
|
5
|
+
what's real vs. conceptual in lessons. Trigger on: 'does X work in WASM', 'can I use this
|
|
6
|
+
gem', 'gem compatibility', 'WASM limitation', 'what works', 'supported features', 'PGLite',
|
|
7
|
+
'threading', 'Net::HTTP', 'ActionCable', 'background jobs', 'can I teach X', 'bundle
|
|
8
|
+
install in WASM', 'conceptual vs real', or any Rails capability question — even without
|
|
9
|
+
mentioning WASM. Authoritative compatibility matrix: which features work, which are shimmed,
|
|
10
|
+
which are impossible, plus gem tiers, PGLite behavior, boot timing, and conceptual-vs-real
|
|
11
|
+
operations. General Rails knowledge is insufficient here. Do NOT use for file organization
|
|
12
|
+
(use rails-file-management) or frontmatter (use tutorial-lesson-config).
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Rails WASM Author Constraints
|
|
16
|
+
|
|
17
|
+
What works, what doesn't, and how to design lessons around the WASM environment.
|
|
18
|
+
|
|
19
|
+
## Quick Reference: What Can I Teach?
|
|
20
|
+
|
|
21
|
+
| Rails Feature | Works? | Notes |
|
|
22
|
+
|---------------|--------|-------|
|
|
23
|
+
| ActiveRecord (CRUD, queries, scopes) | Yes | Full support via PGLite |
|
|
24
|
+
| Migrations & schema management | Yes | Standard `rails db:migrate` |
|
|
25
|
+
| Controllers & routing | Yes | Full support |
|
|
26
|
+
| Views (ERB templates) | Yes | Full support |
|
|
27
|
+
| Form helpers & validations | Yes | Full support |
|
|
28
|
+
| Model associations | Yes | `has_many`, `belongs_to`, etc. |
|
|
29
|
+
| Scaffolding & generators | Yes | `rails generate scaffold`, etc. |
|
|
30
|
+
| Asset pipeline (Propshaft) | Yes | Importmaps, Stimulus, Turbo |
|
|
31
|
+
| Rails console | Yes | Interactive IRB via custom bridge |
|
|
32
|
+
| Authentication (basic) | Yes | `has_secure_password`, session-based |
|
|
33
|
+
| ActionMailer (define mailers) | Partial | Can define/configure but delivery is a no-op |
|
|
34
|
+
| Active Storage (upload) | Partial | Upload works but image processing is a no-op |
|
|
35
|
+
| Background jobs | No | Single-threaded; Solid Queue won't process |
|
|
36
|
+
| ActionCable / WebSockets | No | No `IO.select`, no real socket support |
|
|
37
|
+
| External HTTP requests | No | No outbound networking from Ruby — sockets are unimplemented at the WASI level |
|
|
38
|
+
| Threads / parallel processing | No | `Thread.new` uses fibers (cooperative, single-threaded) |
|
|
39
|
+
| System commands from Ruby | No | `system()`, backticks, `Open3` are non-functional |
|
|
40
|
+
|
|
41
|
+
## Hard Limitations
|
|
42
|
+
|
|
43
|
+
These are **impossible to work around** in the WASM environment. Do not write lessons that depend on them:
|
|
44
|
+
|
|
45
|
+
### No Outbound Networking
|
|
46
|
+
|
|
47
|
+
Socket operations (`TCPSocket`, `UDPSocket`, and all socket classes) fail because the underlying WASI syscalls are unimplemented. `Net::HTTP` and `open-uri` will raise errors when attempting connections. You cannot:
|
|
48
|
+
- Call external APIs from Ruby
|
|
49
|
+
- Download files from the internet
|
|
50
|
+
- Connect to external databases or services
|
|
51
|
+
|
|
52
|
+
**Workaround for lessons:** If you want to teach API consumption, focus on the controller/model patterns and mock the responses. Show the code structure without executing real HTTP calls.
|
|
53
|
+
|
|
54
|
+
### No Process Spawning
|
|
55
|
+
|
|
56
|
+
`system()`, backticks, `exec`, `fork`, and `Open3` are non-functional. The `rails new` generator works because it's been patched, but arbitrary shell commands from tutorial code will not work.
|
|
57
|
+
|
|
58
|
+
### No Threading
|
|
59
|
+
|
|
60
|
+
`Thread.new` is shimmed to use `Fiber.new` (cooperative, single-threaded). Code that relies on parallel execution behaves differently. Background job processing and concurrent operations don't work as expected.
|
|
61
|
+
|
|
62
|
+
### No IO.select
|
|
63
|
+
|
|
64
|
+
The `poll_oneoff` WASI syscall is unimplemented. This breaks gems like nio4r, Puma, and ActionCable's EventMachine adapter.
|
|
65
|
+
|
|
66
|
+
### No chmod/fchmod
|
|
67
|
+
|
|
68
|
+
POSIX permission calls are stubbed. Avoid `FileUtils.chmod` in tutorial code. The `rails new` generator is pre-patched to handle this.
|
|
69
|
+
|
|
70
|
+
## Gem Compatibility
|
|
71
|
+
|
|
72
|
+
### Adding Gems
|
|
73
|
+
|
|
74
|
+
Authors **can add gems** to their tutorial by editing `ruby-wasm/Gemfile` and running `bin/build-wasm` to rebuild the WASM binary. This bakes all gems into the binary at build time.
|
|
75
|
+
|
|
76
|
+
### Compatibility Tiers
|
|
77
|
+
|
|
78
|
+
| Tier | Description | Examples |
|
|
79
|
+
|------|-------------|---------|
|
|
80
|
+
| **Works** | Pure Ruby gems, no native extensions | `devise`, `friendly_id`, `pagy`, `pundit`, `draper`, `kaminari` |
|
|
81
|
+
| **Shimmed** | Has native extensions but already patched | `nokogiri` (stub), `io-console` (stub), `bcrypt` |
|
|
82
|
+
| **Needs testing** | May work if extension compiles for WASM | Test with `bin/build-wasm` |
|
|
83
|
+
| **Won't work** | Requires unsupported syscalls or networking | `pg` (native), `mysql2`, `redis`, `sidekiq`, `puma` |
|
|
84
|
+
|
|
85
|
+
### Pre-Shimmed Gems
|
|
86
|
+
|
|
87
|
+
These gems are already handled by the WASM runtime:
|
|
88
|
+
|
|
89
|
+
| Gem | Behavior |
|
|
90
|
+
|-----|----------|
|
|
91
|
+
| `nokogiri` | 165-line minimal stub; CSS selectors return `[]`; sufficient for sanitization but not real HTML parsing |
|
|
92
|
+
| `io-console` | Stubbed; `winsize` returns `[80, 24]`; `raw` yields without change |
|
|
93
|
+
| `nio4r` | `.so` stripped; loads as empty shim |
|
|
94
|
+
| `date`, `psych`, `bigdecimal` | `.so` stripped; Ruby falls back to pure-Ruby stdlib |
|
|
95
|
+
| `sqlite3` (native) | Replaced by PGLite adapter |
|
|
96
|
+
|
|
97
|
+
### Gem Build Workflow
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# 1. Edit the Gemfile
|
|
101
|
+
vim ruby-wasm/Gemfile
|
|
102
|
+
|
|
103
|
+
# 2. Rebuild the WASM binary (takes several minutes)
|
|
104
|
+
bin/build-wasm
|
|
105
|
+
|
|
106
|
+
# 3. Test your tutorial locally
|
|
107
|
+
npm run dev
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Database: PGLite
|
|
111
|
+
|
|
112
|
+
The database is **PGLite** — an in-browser PostgreSQL implementation compiled to WASM.
|
|
113
|
+
|
|
114
|
+
### What Works
|
|
115
|
+
|
|
116
|
+
- Standard ActiveRecord operations: `create`, `find`, `where`, `update`, `destroy`
|
|
117
|
+
- Migrations: `rails db:migrate`, `rails db:rollback`
|
|
118
|
+
- Seeds: `rails db:seed`
|
|
119
|
+
- PostgreSQL-compatible SQL syntax
|
|
120
|
+
- Multiple databases (development, test)
|
|
121
|
+
- Associations, joins, aggregations
|
|
122
|
+
- Indexes and constraints
|
|
123
|
+
|
|
124
|
+
### What to Know
|
|
125
|
+
|
|
126
|
+
| Behavior | Detail |
|
|
127
|
+
|----------|--------|
|
|
128
|
+
| **Data does not survive page reloads** | WebContainer filesystem is in-memory; refreshing the browser resets everything |
|
|
129
|
+
| **Database adapter** | `pglite` (auto-configured by wasmify-rails; authors don't need to set this up) |
|
|
130
|
+
| **Setup command** | `node scripts/rails.js db:prepare` in `prepareCommands` |
|
|
131
|
+
| **Location** | `pgdata/<dbname>/` in WebContainer filesystem |
|
|
132
|
+
| **Performance** | Slower than native PostgreSQL; acceptable for tutorial-sized datasets |
|
|
133
|
+
|
|
134
|
+
### Lesson Design Implications
|
|
135
|
+
|
|
136
|
+
- Always include `['node scripts/rails.js db:prepare', 'Prepare development database']` in `prepareCommands` for lessons that use the database
|
|
137
|
+
- Provide seeds in templates so users start with data
|
|
138
|
+
- Don't rely on data from a previous lesson persisting — each lesson should set up its own state via migrations + seeds
|
|
139
|
+
|
|
140
|
+
## Boot Timing
|
|
141
|
+
|
|
142
|
+
The WASM runtime takes time to load. Set expectations for tutorial users:
|
|
143
|
+
|
|
144
|
+
| Phase | Typical Duration | What Happens |
|
|
145
|
+
|-------|-----------------|--------------|
|
|
146
|
+
| `npm install` | 10-30s | Downloads ~80MB WASM binary + dependencies |
|
|
147
|
+
| WASM compile | 2-5s | Browser compiles the binary |
|
|
148
|
+
| Rails bootstrap | 2-5s | Loads Rails framework from embedded VFS |
|
|
149
|
+
| Command execution | Varies | User's command runs |
|
|
150
|
+
|
|
151
|
+
**Total first-load time: 15-40 seconds** depending on network and browser.
|
|
152
|
+
|
|
153
|
+
### Author Tips for Boot Experience
|
|
154
|
+
|
|
155
|
+
- Include a note in early lessons: "The Ruby runtime takes a moment to load — this is normal!"
|
|
156
|
+
- Use `prepareCommands` with descriptive labels so users see progress
|
|
157
|
+
- The `['output', 'Setup Logs']` terminal panel shows boot details
|
|
158
|
+
- Subsequent lesson navigation is faster if the WebContainer is already booted
|
|
159
|
+
|
|
160
|
+
## Auto-Authentication
|
|
161
|
+
|
|
162
|
+
The runtime includes an auto-login patch: if `tmp/authenticated-user.txt` exists in the Rails app root, the first HTTP request auto-authenticates the user found by `User.find_by(email_address: <file contents>)`. The file should contain a single email address (e.g., `admin@example.com`).
|
|
163
|
+
|
|
164
|
+
**To use:** Place `workspace/tmp/authenticated-user.txt` in `_files/` or a template, containing the email of a seeded user. The first request calls `start_new_session_for(user)`, creating a session cookie for all subsequent requests. Runs once per VM lifetime (the `$__pre_authenticated` global flag prevents repeat attempts).
|
|
165
|
+
|
|
166
|
+
This requires the Rails 8 `Authentication` concern and a `User` model with an `email_address` column.
|
|
167
|
+
|
|
168
|
+
## Filesystem Boundaries
|
|
169
|
+
|
|
170
|
+
Ruby code can only access `/workspace` (the WASI preopen). Attempting to access paths outside this boundary raises `Errno::ENOENT`. Tutorial code should never navigate above `/workspace` with `Dir.chdir("..")` or absolute paths outside the preopen.
|
|
171
|
+
|
|
172
|
+
## Conceptual vs. Real Operations
|
|
173
|
+
|
|
174
|
+
Some tutorial operations are **conceptual** — they teach the correct pattern but the actual execution requires something different in the WASM environment:
|
|
175
|
+
|
|
176
|
+
| Operation in lesson content | Reality | What the author must do |
|
|
177
|
+
|-----------------------------|---------|------------------------|
|
|
178
|
+
| "Add `gem 'devise'` to your Gemfile" | Gems are baked into the WASM binary at build time | The gem must already be in `ruby-wasm/Gemfile` and rebuilt with `bin/build-wasm` **before** the tutorial is published |
|
|
179
|
+
| "Run `bundle install`" | `bundle install` is a no-op in WASM — all gems come from the binary | Include it for pedagogical completeness; it will appear to succeed |
|
|
180
|
+
| "Run `rails server`" | The Rails server runs through `node scripts/rails.js server` | Use `node scripts/rails.js server` in frontmatter `mainCommand`; in lesson content, show `rails server` since that's what the terminal wrapper understands |
|
|
181
|
+
| "Edit `database.yml`" | Database adapter is PGLite, auto-configured by wasmify-rails | Pre-configure in the template; showing a `database.yml` edit is fine for teaching but won't change the runtime behavior |
|