Skip to content

Commit 55fd108

Browse files
committed
[Documentation] Form: make Rails examples code-only and rebuild MCP registry (#434)
Convert the two Rails-integration examples ("Minimal Rails form" and "Devise-style login form") from VisualCodeExample to Heading + Codeblock so they are displayed as syntax-highlighted code without being live-rendered via instance_eval. This fixes the ComponentsControllerTest crash caused by helpers.users_path and helpers.user_session_path not existing in the docs app. Also rebuild mcp/data/registry.json to include the updated form docs.
1 parent 2c6321c commit 55fd108

3 files changed

Lines changed: 121 additions & 125 deletions

File tree

docs/app/views/docs/form.rb

Lines changed: 60 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -190,76 +190,74 @@ def view_template
190190
plain "."
191191
end
192192

193-
render Docs::VisualCodeExample.new(title: "Minimal Rails form", context: self) do
194-
<<~RUBY
195-
# In your Phlex view, call form_with via helpers:
196-
# form_with(url: users_path, method: :post) passes action + CSRF automatically.
197-
#
198-
# You can also set action and the CSRF token manually:
199-
Form(action: helpers.users_path, method: "post", class: "w-2/3 space-y-6") do
200-
input(type: "hidden", name: "authenticity_token", value: helpers.form_authenticity_token)
193+
Heading(level: 3) { "Minimal Rails form" }
194+
Codeblock(<<~RUBY, syntax: :ruby)
195+
# In your Phlex view, call form_with via helpers:
196+
# form_with(url: users_path, method: :post) passes action + CSRF automatically.
197+
#
198+
# You can also set action and the CSRF token manually:
199+
Form(action: helpers.users_path, method: "post", class: "w-2/3 space-y-6") do
200+
input(type: "hidden", name: "authenticity_token", value: helpers.form_authenticity_token)
201201
202-
FormField do
203-
FormFieldLabel(for: "user_email") { "Email" }
204-
Input(
205-
type: "email",
206-
id: "user_email",
207-
name: "user[email]",
208-
placeholder: "you@example.com",
209-
required: true
210-
)
211-
FormFieldError()
212-
end
213-
214-
Button(type: "submit") { "Continue" }
202+
FormField do
203+
FormFieldLabel(for: "user_email") { "Email" }
204+
Input(
205+
type: "email",
206+
id: "user_email",
207+
name: "user[email]",
208+
placeholder: "you@example.com",
209+
required: true
210+
)
211+
FormFieldError()
215212
end
216-
RUBY
217-
end
218213
219-
render Docs::VisualCodeExample.new(title: "Devise-style login form", context: self) do
220-
<<~RUBY
221-
# Full sign-in form mirroring Devise session[email] / session[password] params.
222-
# Pass backend errors (e.g. "Invalid email or password") into FormFieldError.
223-
Form(action: helpers.user_session_path, method: "post", class: "space-y-6") do
224-
input(type: "hidden", name: "authenticity_token", value: helpers.form_authenticity_token)
214+
Button(type: "submit") { "Continue" }
215+
end
216+
RUBY
225217

226-
FormField do
227-
FormFieldLabel(for: "session_email") { "Email" }
228-
Input(
229-
type: "email",
230-
id: "session_email",
231-
name: "session[email]",
232-
placeholder: "you@example.com",
233-
autocomplete: "email",
234-
required: true
235-
)
236-
FormFieldError { @error_message }
237-
end
218+
Heading(level: 3) { "Devise-style login form" }
219+
Codeblock(<<~RUBY, syntax: :ruby)
220+
# Full sign-in form mirroring Devise session[email] / session[password] params.
221+
# Pass backend errors (e.g. "Invalid email or password") into FormFieldError.
222+
Form(action: helpers.user_session_path, method: "post", class: "space-y-6") do
223+
input(type: "hidden", name: "authenticity_token", value: helpers.form_authenticity_token)
238224
239-
FormField do
240-
FormFieldLabel(for: "session_password") { "Password" }
241-
Input(
242-
type: "password",
243-
id: "session_password",
244-
name: "session[password]",
245-
autocomplete: "current-password",
246-
required: true,
247-
minlength: "8"
248-
)
249-
FormFieldError()
250-
end
225+
FormField do
226+
FormFieldLabel(for: "session_email") { "Email" }
227+
Input(
228+
type: "email",
229+
id: "session_email",
230+
name: "session[email]",
231+
placeholder: "you@example.com",
232+
autocomplete: "email",
233+
required: true
234+
)
235+
FormFieldError { @error_message }
236+
end
251237
252-
FormField do
253-
div(class: "flex items-center gap-2") do
254-
Checkbox(id: "session_remember_me", name: "session[remember_me]", value: "1")
255-
FormFieldLabel(for: "session_remember_me") { "Remember me" }
256-
end
257-
end
238+
FormField do
239+
FormFieldLabel(for: "session_password") { "Password" }
240+
Input(
241+
type: "password",
242+
id: "session_password",
243+
name: "session[password]",
244+
autocomplete: "current-password",
245+
required: true,
246+
minlength: "8"
247+
)
248+
FormFieldError()
249+
end
258250
259-
Button(type: "submit", class: "w-full") { "Sign in" }
251+
FormField do
252+
div(class: "flex items-center gap-2") do
253+
Checkbox(id: "session_remember_me", name: "session[remember_me]", value: "1")
254+
FormFieldLabel(for: "session_remember_me") { "Remember me" }
255+
end
260256
end
261-
RUBY
262-
end
257+
258+
Button(type: "submit", class: "w-full") { "Sign in" }
259+
end
260+
RUBY
263261

264262
render Components::ComponentSetup::Tabs.new(component_name: component)
265263

gem/lib/ruby_ui/form/form_docs.rb

Lines changed: 60 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -190,76 +190,74 @@ def view_template
190190
plain "."
191191
end
192192

193-
render Docs::VisualCodeExample.new(title: "Minimal Rails form", context: self) do
194-
<<~RUBY
195-
# In your Phlex view, call form_with via helpers:
196-
# form_with(url: users_path, method: :post) passes action + CSRF automatically.
197-
#
198-
# You can also set action and the CSRF token manually:
199-
Form(action: helpers.users_path, method: "post", class: "w-2/3 space-y-6") do
200-
input(type: "hidden", name: "authenticity_token", value: helpers.form_authenticity_token)
193+
Heading(level: 3) { "Minimal Rails form" }
194+
Codeblock(<<~RUBY, syntax: :ruby)
195+
# In your Phlex view, call form_with via helpers:
196+
# form_with(url: users_path, method: :post) passes action + CSRF automatically.
197+
#
198+
# You can also set action and the CSRF token manually:
199+
Form(action: helpers.users_path, method: "post", class: "w-2/3 space-y-6") do
200+
input(type: "hidden", name: "authenticity_token", value: helpers.form_authenticity_token)
201201
202-
FormField do
203-
FormFieldLabel(for: "user_email") { "Email" }
204-
Input(
205-
type: "email",
206-
id: "user_email",
207-
name: "user[email]",
208-
placeholder: "you@example.com",
209-
required: true
210-
)
211-
FormFieldError()
212-
end
213-
214-
Button(type: "submit") { "Continue" }
202+
FormField do
203+
FormFieldLabel(for: "user_email") { "Email" }
204+
Input(
205+
type: "email",
206+
id: "user_email",
207+
name: "user[email]",
208+
placeholder: "you@example.com",
209+
required: true
210+
)
211+
FormFieldError()
215212
end
216-
RUBY
217-
end
218213
219-
render Docs::VisualCodeExample.new(title: "Devise-style login form", context: self) do
220-
<<~RUBY
221-
# Full sign-in form mirroring Devise session[email] / session[password] params.
222-
# Pass backend errors (e.g. "Invalid email or password") into FormFieldError.
223-
Form(action: helpers.user_session_path, method: "post", class: "space-y-6") do
224-
input(type: "hidden", name: "authenticity_token", value: helpers.form_authenticity_token)
214+
Button(type: "submit") { "Continue" }
215+
end
216+
RUBY
225217

226-
FormField do
227-
FormFieldLabel(for: "session_email") { "Email" }
228-
Input(
229-
type: "email",
230-
id: "session_email",
231-
name: "session[email]",
232-
placeholder: "you@example.com",
233-
autocomplete: "email",
234-
required: true
235-
)
236-
FormFieldError { @error_message }
237-
end
218+
Heading(level: 3) { "Devise-style login form" }
219+
Codeblock(<<~RUBY, syntax: :ruby)
220+
# Full sign-in form mirroring Devise session[email] / session[password] params.
221+
# Pass backend errors (e.g. "Invalid email or password") into FormFieldError.
222+
Form(action: helpers.user_session_path, method: "post", class: "space-y-6") do
223+
input(type: "hidden", name: "authenticity_token", value: helpers.form_authenticity_token)
238224
239-
FormField do
240-
FormFieldLabel(for: "session_password") { "Password" }
241-
Input(
242-
type: "password",
243-
id: "session_password",
244-
name: "session[password]",
245-
autocomplete: "current-password",
246-
required: true,
247-
minlength: "8"
248-
)
249-
FormFieldError()
250-
end
225+
FormField do
226+
FormFieldLabel(for: "session_email") { "Email" }
227+
Input(
228+
type: "email",
229+
id: "session_email",
230+
name: "session[email]",
231+
placeholder: "you@example.com",
232+
autocomplete: "email",
233+
required: true
234+
)
235+
FormFieldError { @error_message }
236+
end
251237
252-
FormField do
253-
div(class: "flex items-center gap-2") do
254-
Checkbox(id: "session_remember_me", name: "session[remember_me]", value: "1")
255-
FormFieldLabel(for: "session_remember_me") { "Remember me" }
256-
end
257-
end
238+
FormField do
239+
FormFieldLabel(for: "session_password") { "Password" }
240+
Input(
241+
type: "password",
242+
id: "session_password",
243+
name: "session[password]",
244+
autocomplete: "current-password",
245+
required: true,
246+
minlength: "8"
247+
)
248+
FormFieldError()
249+
end
258250
259-
Button(type: "submit", class: "w-full") { "Sign in" }
251+
FormField do
252+
div(class: "flex items-center gap-2") do
253+
Checkbox(id: "session_remember_me", name: "session[remember_me]", value: "1")
254+
FormFieldLabel(for: "session_remember_me") { "Remember me" }
255+
end
260256
end
261-
RUBY
262-
end
257+
258+
Button(type: "submit", class: "w-full") { "Sign in" }
259+
end
260+
RUBY
263261

264262
render Components::ComponentSetup::Tabs.new(component_name: component)
265263

mcp/data/registry.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1394,7 +1394,7 @@
13941394
"gems": []
13951395
},
13961396
"install_command": "rails g ruby_ui:component Form",
1397-
"docs_markdown": "# Form\n\nBuilding forms with built-in client-side validations.\n\n## Usage\n\n### Example\n\n```ruby\nForm(class: \"w-2/3 space-y-6\") do\n FormField do\n FormFieldLabel { \"Default error\" }\n Input(placeholder: \"Joel Drapper\", required: true, minlength: \"3\") { \"Joel Drapper\" }\n FormFieldHint()\n FormFieldError()\n end\n Button(type: \"submit\") { \"Save\" }\nend\n```\n\n### Disabled\n\n```ruby\nFormField do\n FormFieldLabel { \"Disabled\" }\n Input(disabled: true, placeholder: \"Joel Drapper\", required: true, minlength: \"3\") { \"Joel Drapper\" }\nend\n```\n\n### Aria Disabled\n\n```ruby\nFormField do\n FormFieldLabel { \"Aria Disabled\" }\n Input(aria: {disabled: \"true\"}, placeholder: \"Joel Drapper\", required: true, minlength: \"3\") { \"Joel Drapper\" }\nend\n```\n\n### Custom error message\n\n```ruby\nForm(class: \"w-2/3 space-y-6\") do\n FormField do\n FormFieldLabel { \"Custom error message\" }\n Input(placeholder: \"joel@drapper.me\", required: true, data_value_missing: \"Custom error message\")\n FormFieldError()\n end\n Button(type: \"submit\") { \"Save\" }\nend\n```\n\n### Backend error\n\n```ruby\nForm(class: \"w-2/3 space-y-6\") do\n FormField do\n FormFieldLabel { \"Backend error\" }\n Input(placeholder: \"Joel Drapper\", required: true)\n FormFieldError { \"Error from backend\" }\n end\n Button(type: \"submit\") { \"Save\" }\nend\n```\n\n### Checkbox\n\n```ruby\nForm(class: \"w-2/3 space-y-6\") do\n FormField do\n Checkbox(required: true)\n label(\n class:\n \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n ) { \" Accept terms and conditions \" }\n FormFieldError()\n end\n Button(type: \"submit\") { \"Save\" }\nend\n```\n\n### Select\n\n```ruby\nForm(class: \"w-2/3 space-y-6\") do\n FormField do\n FormFieldLabel { \"Select\" }\n Select do\n SelectInput(required: true)\n SelectTrigger do\n SelectValue(placeholder: \"Select a fruit\")\n end\n SelectContent() do\n SelectGroup do\n SelectLabel { \"Fruits\" }\n SelectItem(value: \"apple\") { \"Apple\" }\n SelectItem(value: \"orange\") { \"Orange\" }\n SelectItem(value: \"banana\") { \"Banana\" }\n SelectItem(value: \"watermelon\") { \"Watermelon\" }\n end\n end\n end\n FormFieldError()\n end\n Button(type: \"submit\") { \"Save\" }\nend\n```\n\n### Combobox\n\n```ruby\nForm(class: \"w-2/3 space-y-6\") do\n FormField do\n FormFieldLabel { \"Combobox\" }\n\n Combobox do\n ComboboxTrigger placeholder: \"Pick value\"\n\n ComboboxPopover do\n ComboboxSearchInput(placeholder: \"Pick value or type anything\")\n\n ComboboxList do\n ComboboxEmptyState { \"No result\" }\n\n ComboboxListGroup label: \"Fruits\" do\n ComboboxItem do\n ComboboxRadio(name: \"food\", value: \"apple\", required: true)\n span { \"Apple\" }\n end\n\n ComboboxItem do\n ComboboxRadio(name: \"food\", value: \"banana\", required: true)\n span { \"Banana\" }\n end\n end\n\n ComboboxListGroup label: \"Vegetable\" do\n ComboboxItem do\n ComboboxRadio(name: \"food\", value: \"brocoli\", required: true)\n span { \"Broccoli\" }\n end\n\n ComboboxItem do\n ComboboxRadio(name: \"food\", value: \"carrot\", required: true)\n span { \"Carrot\" }\n end\n end\n\n ComboboxListGroup label: \"Others\" do\n ComboboxItem do\n ComboboxRadio(name: \"food\", value: \"chocolate\", required: true)\n span { \"Chocolate\" }\n end\n\n ComboboxItem do\n ComboboxRadio(name: \"food\", value: \"milk\", required: true)\n span { \"Milk\" }\n end\n end\n end\n end\n end\n\n FormFieldError()\n end\n Button(type: \"submit\") { \"Save\" }\nend\n```",
1397+
"docs_markdown": "# Form\n\nBuilding forms with built-in client-side validations.\n\n## Usage\n\n### Example\n\n```ruby\nForm(class: \"w-2/3 space-y-6\") do\n FormField do\n FormFieldLabel { \"Default error\" }\n Input(placeholder: \"Joel Drapper\", required: true, minlength: \"3\") { \"Joel Drapper\" }\n FormFieldHint()\n FormFieldError()\n end\n Button(type: \"submit\") { \"Save\" }\nend\n```\n\n### Disabled\n\n```ruby\nFormField do\n FormFieldLabel { \"Disabled\" }\n Input(disabled: true, placeholder: \"Joel Drapper\", required: true, minlength: \"3\") { \"Joel Drapper\" }\nend\n```\n\n### Aria Disabled\n\n```ruby\nFormField do\n FormFieldLabel { \"Aria Disabled\" }\n Input(aria: {disabled: \"true\"}, placeholder: \"Joel Drapper\", required: true, minlength: \"3\") { \"Joel Drapper\" }\nend\n```\n\n### Custom error message\n\n```ruby\nForm(class: \"w-2/3 space-y-6\") do\n FormField do\n FormFieldLabel { \"Custom error message\" }\n Input(placeholder: \"joel@drapper.me\", required: true, data_value_missing: \"Custom error message\")\n FormFieldError()\n end\n Button(type: \"submit\") { \"Save\" }\nend\n```\n\n### Backend error\n\n```ruby\nForm(class: \"w-2/3 space-y-6\") do\n FormField do\n FormFieldLabel { \"Backend error\" }\n Input(placeholder: \"Joel Drapper\", required: true)\n FormFieldError { \"Error from backend\" }\n end\n Button(type: \"submit\") { \"Save\" }\nend\n```\n\n### Checkbox\n\n```ruby\nForm(class: \"w-2/3 space-y-6\") do\n FormField do\n Checkbox(required: true)\n label(\n class:\n \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n ) { \" Accept terms and conditions \" }\n FormFieldError()\n end\n Button(type: \"submit\") { \"Save\" }\nend\n```\n\n### Select\n\n```ruby\nForm(class: \"w-2/3 space-y-6\") do\n FormField do\n FormFieldLabel { \"Select\" }\n Select do\n SelectInput(required: true)\n SelectTrigger do\n SelectValue(placeholder: \"Select a fruit\")\n end\n SelectContent() do\n SelectGroup do\n SelectLabel { \"Fruits\" }\n SelectItem(value: \"apple\") { \"Apple\" }\n SelectItem(value: \"orange\") { \"Orange\" }\n SelectItem(value: \"banana\") { \"Banana\" }\n SelectItem(value: \"watermelon\") { \"Watermelon\" }\n end\n end\n end\n FormFieldError()\n end\n Button(type: \"submit\") { \"Save\" }\nend\n```\n\n### Combobox\n\n```ruby\nForm(class: \"w-2/3 space-y-6\") do\n FormField do\n FormFieldLabel { \"Combobox\" }\n\n Combobox do\n ComboboxTrigger placeholder: \"Pick value\"\n\n ComboboxPopover do\n ComboboxSearchInput(placeholder: \"Pick value or type anything\")\n\n ComboboxList do\n ComboboxEmptyState { \"No result\" }\n\n ComboboxListGroup label: \"Fruits\" do\n ComboboxItem do\n ComboboxRadio(name: \"food\", value: \"apple\", required: true)\n span { \"Apple\" }\n end\n\n ComboboxItem do\n ComboboxRadio(name: \"food\", value: \"banana\", required: true)\n span { \"Banana\" }\n end\n end\n\n ComboboxListGroup label: \"Vegetable\" do\n ComboboxItem do\n ComboboxRadio(name: \"food\", value: \"brocoli\", required: true)\n span { \"Broccoli\" }\n end\n\n ComboboxItem do\n ComboboxRadio(name: \"food\", value: \"carrot\", required: true)\n span { \"Carrot\" }\n end\n end\n\n ComboboxListGroup label: \"Others\" do\n ComboboxItem do\n ComboboxRadio(name: \"food\", value: \"chocolate\", required: true)\n span { \"Chocolate\" }\n end\n\n ComboboxItem do\n ComboboxRadio(name: \"food\", value: \"milk\", required: true)\n span { \"Milk\" }\n end\n end\n end\n end\n end\n\n FormFieldError()\n end\n Button(type: \"submit\") { \"Save\" }\nend\n```\n\n## Rails Integration\n\n### Minimal Rails form\n\n### Devise-style login form",
13981398
"examples": [
13991399
{
14001400
"title": "Example",

0 commit comments

Comments
 (0)