docs / when it breaks
In the template
Errors ruact raises while it compiles a template — component names, tags that do not pair, attributes, <Suspense>, and component contracts. Each stops the page before any HTML is sent.
template compilemessages from ruact 0.0.22
When you finish
- what each compile-time message means and the change it asks for
- why the line number in an attribute message has no file next to it
ruact reads every template before Rails compiles it, turning each capitalized tag into a React element. When a tag is wrong, it stops there: the page is an ActionView::Template::Error whose message is one of the ones below, and nothing has reached the browser.
Every message on this page was produced by running ruact 0.0.22’s preprocessor (Ruact::ErbPreprocessor.transform) on the template above it, with the identifier app/views/posts/index.html.erb.
Component names
Section titled “Component names”Component not found in manifest, with a suggestion
Section titled “Component not found in manifest, with a suggestion”<h1>Posts</h1>
<PostCrad post={@post} />ruact: <PostCrad> at app/views/posts/index.html.erb:3 — Component "PostCrad" not found in manifest. Did you mean "PostCard"?Why. A capitalized tag is a React component, and its name must be the export of a "use client" file the Vite build knows. This one is two edits from a name the build has, so ruact names it.
Fix. Use the name it suggests.
<PostCrad post={@post} /><PostCard post={@post} />The editor on the home page raises this message for a misspelled <LikeButon>, and the gem pins that text byte for byte in spec/readme_demo_message_spec.rb.
Component not found in manifest, no close name
Section titled “Component not found in manifest, no close name”ruact: <PostTable> at app/views/posts/index.html.erb:3 — Component "PostTable" not found in manifest. Did you mean to add app/javascript/components/PostTable.jsx and rebuild Vite? Did you run the Vite build? Run 'npm run build' or start the Vite dev server.Why. No component in the build is called that. Either the file does not exist yet, or it exists and the build that ruact is reading predates it.
Fix. Create app/javascript/components/PostTable.jsx with "use client" and a named export PostTable. In development, bin/dev runs Vite, which picks it up; elsewhere, run npm run build.
Tags that do not pair
Section titled “Tags that do not pair”A tag that is never closed
Section titled “A tag that is never closed”<h1>Posts</h1><Dialog open={true}><p>Delete?</p>ruact: <Dialog> at app/views/posts/index.html.erb:2 is never closed — write `<Dialog ... />` for a component without children, or close it with `</Dialog>`.Fix. Close it the way the message says: <Dialog open={true} /> when it has no children, or </Dialog> after them.
A closing tag that closes nothing
Section titled “A closing tag that closes nothing”ruact: </Card> at app/views/posts/index.html.erb:2 closes nothing — there is no open <Card> before it.Fix. Remove the stray </Card>, or add the <Card> it was meant to close.
Children given twice
Section titled “Children given twice”<Card children={@body}> <p>Hello</p></Card>ruact: <Card> at app/views/posts/index.html.erb:1 has content between its tags and a `children={...}` prop — pass one of them.Fix. Keep one: the content between the tags, or the children={...} attribute.
Attributes
Section titled “Attributes”A component attribute takes one of three forms: {ruby}, "text", or no value at all. Anything else stops at compile time with one of these messages. They read differently from the rest of this page: they start with the problem rather than ruact:, and give the line but not the file — the file is the one named in the error page’s title.
| Message | Written as | Fix |
|---|---|---|
title= holds ERB, which a component attribute cannot run. Pass the Ruby in braces instead: title={...} at line 1: <PostCard title="<%= @post.title %>" /> |
title="<%= @post.title %>" |
title={@post.title} |
post={} is empty: put a Ruby expression in the braces at line 1: <PostCard post={} /> |
post={} |
post={@post} |
unclosed quote in title= (a component tag cannot contain `>`, even inside a quoted value: pass the text from Ruby instead) at line 1: <PostCard title="a > |
title="a > b" |
title={"a > b"} |
title= needs a value: title={ruby} or title="text" at line 1: <PostCard title= /> |
title= |
title={@title} or title="Posts" |
unclosed brace in prop expression at line 1: <PostCard post={@post /> |
post={@post |
post={@post} |
unexpected "2fast={true}" in the component's attributes at line 1: <PostCard 2fast={true} /> |
2fast={true} |
an attribute name starts with a letter or _ |
All six are Ruact::PreprocessorError.
<Suspense>
Section titled “<Suspense>”A <Suspense> that is never closed
Section titled “A <Suspense> that is never closed”ruact: <Suspense> at app/views/posts/index.html.erb:2 is never closed — close it with `</Suspense>`.Opened and closed in different ERB blocks
Section titled “Opened and closed in different ERB blocks”<% if @show %><Suspense fallback="Loading…"><% end %></Suspense>ruact: <Suspense> at app/views/posts/index.html.erb:2 and its </Suspense> at line 4 are not in the same ERB block — an `if`, a loop or a block opens or closes between them. Put both tags inside that block, or both outside it.Why. What is between a <Suspense>’s tags becomes a block that runs later. An if or a loop that opens on one side and closes on the other cannot be split that way.
next, break, redo or return inside a <Suspense>
Section titled “next, break, redo or return inside a <Suspense>”<% @posts.each do |post| %><Suspense fallback="…"> <% next if post.draft? %> <PostCard post={post} /></Suspense><% end %>ruact: <Suspense> at app/views/posts/index.html.erb:2 — `next` between its tags would apply to the Suspense's own block, not to the loop or block around it. Move it outside the Suspense.Fix. Skip the draft before the <Suspense> opens: <% next if post.draft? %> goes on the line after the each.
ERB in fallback or delay
Section titled “ERB in fallback or delay”ruact: <Suspense> at app/views/posts/index.html.erb:1 — `fallback` and `delay` take literal text, not ERB.Fix. Write the fallback as text: fallback="Loading…".
Component contracts
Section titled “Component contracts”When a component declares the props it takes, ruact checks each tag against that declaration while it compiles the template. The messages show where the tag is and quote it.
A required prop is missing
Section titled “A required prop is missing”ruact: <LikeButton> at app/views/posts/show.html.erb:7 is missing required prop "postId" — add the required prop "postId". in: <LikeButton ... />The same message names a required slot as required slot.
An unknown prop
Section titled “An unknown prop”ruact: <LikeButton> at app/views/posts/show.html.erb:7 got unknown prop "postID" — did you mean "postId"?. in: <LikeButton ... />With no close name, it ends at the prop: got unknown prop "colour". A component that declares passthrough accepts props it does not list, and this check does not apply to it.