compony 0.11.8 → 0.11.9

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.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +36 -1
  3. data/CHANGELOG.md +31 -0
  4. data/CLAUDE.md +85 -0
  5. data/Gemfile.lock +1 -1
  6. data/README.md +13 -3
  7. data/VERSION +1 -1
  8. data/compony.gemspec +3 -3
  9. data/doc/ComponentGenerator.html +1 -1
  10. data/doc/Components.html +1 -1
  11. data/doc/ComponentsGenerator.html +1 -1
  12. data/doc/Compony/Component.html +54 -54
  13. data/doc/Compony/ComponentMixins/Default/Labelling.html +1 -1
  14. data/doc/Compony/ComponentMixins/Default/Standalone/ResourcefulVerbDsl.html +1 -1
  15. data/doc/Compony/ComponentMixins/Default/Standalone/StandaloneDsl.html +109 -70
  16. data/doc/Compony/ComponentMixins/Default/Standalone/VerbDsl.html +64 -28
  17. data/doc/Compony/ComponentMixins/Default/Standalone.html +1 -1
  18. data/doc/Compony/ComponentMixins/Default.html +1 -1
  19. data/doc/Compony/ComponentMixins/Resourceful.html +213 -74
  20. data/doc/Compony/ComponentMixins.html +1 -1
  21. data/doc/Compony/Components/Buttons/CssButton.html +1 -1
  22. data/doc/Compony/Components/Buttons/Link.html +1 -1
  23. data/doc/Compony/Components/Buttons.html +1 -1
  24. data/doc/Compony/Components/Destroy.html +83 -29
  25. data/doc/Compony/Components/Edit.html +110 -38
  26. data/doc/Compony/Components/Form.html +551 -208
  27. data/doc/Compony/Components/Index.html +1 -1
  28. data/doc/Compony/Components/List.html +3 -3
  29. data/doc/Compony/Components/New.html +110 -38
  30. data/doc/Compony/Components/Show.html +1 -1
  31. data/doc/Compony/Components/WithForm.html +194 -47
  32. data/doc/Compony/Components.html +1 -1
  33. data/doc/Compony/ControllerMixin.html +1 -1
  34. data/doc/Compony/Engine.html +1 -1
  35. data/doc/Compony/Intent.html +2 -2
  36. data/doc/Compony/ManageIntentsDsl.html +1 -1
  37. data/doc/Compony/MethodAccessibleHash.html +1 -1
  38. data/doc/Compony/ModelFields/Anchormodel.html +1 -1
  39. data/doc/Compony/ModelFields/Association.html +1 -1
  40. data/doc/Compony/ModelFields/Attachment.html +1 -1
  41. data/doc/Compony/ModelFields/Base.html +1 -1
  42. data/doc/Compony/ModelFields/Boolean.html +1 -1
  43. data/doc/Compony/ModelFields/Color.html +1 -1
  44. data/doc/Compony/ModelFields/Currency.html +1 -1
  45. data/doc/Compony/ModelFields/Date.html +1 -1
  46. data/doc/Compony/ModelFields/Datetime.html +1 -1
  47. data/doc/Compony/ModelFields/Decimal.html +1 -1
  48. data/doc/Compony/ModelFields/Email.html +1 -1
  49. data/doc/Compony/ModelFields/Float.html +1 -1
  50. data/doc/Compony/ModelFields/Integer.html +1 -1
  51. data/doc/Compony/ModelFields/Percentage.html +1 -1
  52. data/doc/Compony/ModelFields/Phone.html +1 -1
  53. data/doc/Compony/ModelFields/RichText.html +1 -1
  54. data/doc/Compony/ModelFields/String.html +1 -1
  55. data/doc/Compony/ModelFields/Text.html +1 -1
  56. data/doc/Compony/ModelFields/Time.html +1 -1
  57. data/doc/Compony/ModelFields/Url.html +1 -1
  58. data/doc/Compony/ModelFields.html +1 -1
  59. data/doc/Compony/ModelMixin.html +1 -1
  60. data/doc/Compony/NaturalOrdering.html +1 -1
  61. data/doc/Compony/RequestContext.html +1 -1
  62. data/doc/Compony/Version.html +1 -1
  63. data/doc/Compony/ViewHelpers.html +1 -1
  64. data/doc/Compony/VirtualModel.html +1 -1
  65. data/doc/Compony.html +1 -1
  66. data/doc/ComponyController.html +1 -1
  67. data/doc/_index.html +97 -1
  68. data/doc/file.CHANGELOG.html +758 -0
  69. data/doc/file.README.html +25 -4
  70. data/doc/file.basic_component.html +314 -0
  71. data/doc/file.cookbook.html +189 -0
  72. data/doc/file.destroy.html +105 -0
  73. data/doc/file.dsl_reference.html +672 -0
  74. data/doc/file.edit.html +109 -0
  75. data/doc/file.example.html +291 -0
  76. data/doc/file.example_advanced.html +257 -0
  77. data/doc/file.feasibility.html +115 -0
  78. data/doc/file.form.html +195 -0
  79. data/doc/file.generators.html +89 -0
  80. data/doc/file.glossary.html +217 -0
  81. data/doc/file.gotchas.html +222 -0
  82. data/doc/file.index.html +135 -0
  83. data/doc/file.inheritance.html +136 -0
  84. data/doc/file.installation.html +115 -0
  85. data/doc/file.integrations.html +218 -0
  86. data/doc/file.intents.html +265 -0
  87. data/doc/file.internal_datastructures.html +129 -0
  88. data/doc/file.list.html +253 -0
  89. data/doc/file.maintaining.html +127 -0
  90. data/doc/file.model_fields.html +137 -0
  91. data/doc/file.nesting.html +237 -0
  92. data/doc/file.new.html +109 -0
  93. data/doc/file.ownership.html +98 -0
  94. data/doc/file.patterns.html +669 -0
  95. data/doc/file.pre_built_components.html +99 -0
  96. data/doc/file.resourceful.html +181 -0
  97. data/doc/file.show.html +158 -0
  98. data/doc/file.standalone.html +233 -0
  99. data/doc/file.virtual_models.html +117 -0
  100. data/doc/file.with_form.html +157 -0
  101. data/doc/file_list.html +160 -0
  102. data/doc/guide/cookbook.md +41 -0
  103. data/doc/guide/dsl_reference.md +155 -0
  104. data/doc/guide/example_advanced.md +209 -0
  105. data/doc/guide/generators.md +1 -1
  106. data/doc/guide/glossary.md +42 -0
  107. data/doc/guide/gotchas.md +125 -0
  108. data/doc/guide/maintaining.md +64 -0
  109. data/doc/guide/patterns.md +681 -0
  110. data/doc/guide/pre_built_components/edit.md +1 -1
  111. data/doc/guide/pre_built_components/index.md +64 -1
  112. data/doc/guide/pre_built_components/list.md +111 -7
  113. data/doc/guide/pre_built_components/show.md +57 -2
  114. data/doc/guide/pre_built_components/with_form.md +56 -9
  115. data/doc/guide/pre_built_components.md +7 -2
  116. data/doc/guide/standalone.md +16 -1
  117. data/doc/index.html +25 -4
  118. data/doc/integrations.md +61 -0
  119. data/doc/llms.txt +62 -0
  120. data/doc/top-level-namespace.html +1 -1
  121. data/lib/compony/component.rb +8 -3
  122. data/lib/compony/component_mixins/default/standalone/standalone_dsl.rb +32 -15
  123. data/lib/compony/component_mixins/default/standalone/verb_dsl.rb +11 -3
  124. data/lib/compony/component_mixins/resourceful.rb +30 -16
  125. data/lib/compony/components/destroy.rb +21 -1
  126. data/lib/compony/components/edit.rb +25 -1
  127. data/lib/compony/components/form.rb +63 -21
  128. data/lib/compony/components/list.rb +1 -1
  129. data/lib/compony/components/new.rb +25 -1
  130. data/lib/compony/components/with_form.rb +20 -5
  131. data/lib/compony/intent.rb +1 -1
  132. metadata +43 -1
data/doc/file.README.html CHANGED
@@ -90,7 +90,7 @@
90
90
  </li><li>
91
91
  <p>Compony seamlessly integrates with Rails and does not interfere with existing code. Using Compony, you <strong>can</strong> write your application as components, but it is still possible to have regular routes, controllers and views side-to-side to it. This way, you can migrate your applications to Compony little by little and enter and leave the Compony world as you please. It is also possible to render Compony components from regular views and vice versa.</p>
92
92
  </li><li>
93
- <p>Compony is built for Rails 7, 7.1 and 8, and fully supports Stimulus and Turbo Drive. It is also compatible Turbo Frames and Streams, but there are not many helpers specifically targetting theme at this point..</p>
93
+ <p>Compony requires Rails &gt;= 7.2.1 and Ruby &gt;= 3.3.5 (see <a href="./doc/integrations_md.html">doc/integrations.md</a> for all dependencies), and fully supports Stimulus and Turbo Drive. It is also compatible Turbo Frames and Streams, but there are not many helpers specifically targetting theme at this point..</p>
94
94
  </li><li>
95
95
  <p>Compony uses <a href="https://github.com/CanCanCommunity/cancancan">CanCanCan</a> for authorization but does not provide an authentication mechanism. You can easily build your own by creating login/logout components that manage cookies, and configure Compony to enforce authentication using the <code>Compony.authentication_before_action</code> setter. I have also successfully tested Compony to work with <a href="https://github.com/heartcombo/devise">Devise</a>.</p>
96
96
  </li></ul>
@@ -109,8 +109,29 @@
109
109
  <ul><li>
110
110
  <p><a href="./doc/guide/example_md.html">Self-contained example</a> for those who like to dive straight into code</p>
111
111
  </li><li>
112
+ <p><a href="./doc/guide/example_advanced_md.html">Advanced example</a>: custom form, feasibility, CSV export, virtual-model launch form</p>
113
+ </li><li>
112
114
  <p><a href="./doc/guide/installation_md.html">Installation</a> (start here)</p>
113
115
  </li><li>
116
+ <p>Quick reference (also handy for AI coding assistants):</p>
117
+ <ul><li>
118
+ <p><a href="./doc/guide/dsl_reference_md.html">DSL reference</a>: every DSL method with signature and context</p>
119
+ </li><li>
120
+ <p><a href="./doc/guide/glossary_md.html">Glossary</a>: one-line definitions of Compony vocabulary</p>
121
+ </li><li>
122
+ <p><a href="./doc/guide/gotchas_md.html">Gotchas</a>: known anti-patterns with symptom, cause, fix</p>
123
+ </li><li>
124
+ <p><a href="./doc/guide/patterns_md.html">Real-world patterns</a>: idioms distilled from production apps</p>
125
+ </li><li>
126
+ <p><a href="./doc/guide/cookbook_md.html">Cookbook</a>: recipes indexed by task (“I want to do X”)</p>
127
+ </li><li>
128
+ <p><a href="./doc/integrations_md.html">Integrations</a>: companion gems — required, optional, app-side</p>
129
+ </li><li>
130
+ <p><a href="./CLAUDE_md.html">Agent primer</a> and <a href="./doc/llms.txt">doc/llms.txt</a>: orientation for LLM-based tools</p>
131
+ </li><li>
132
+ <p><a href="./doc/guide/maintaining_md.html">Maintaining</a>: release &amp; docs policy (for gem contributors)</p>
133
+ </li></ul>
134
+ </li><li>
114
135
  <p>Concepts and usage:</p>
115
136
  <ul><li>
116
137
  <p><a href="./doc/guide/basic_component_md.html">A basic component</a>: Basic concepts relevant for all components</p>
@@ -135,7 +156,7 @@
135
156
  </li><li>
136
157
  <p><a href="./doc/guide/internal_datastructures_md.html">Internal datastructures</a>: Noteworthy datastructures provided by Compony</p>
137
158
  </li><li>
138
- <p><a href="./doc/guide/internal_datastructures_md.html">Virtual models</a>: Unleashing non-persistent interactions through Compony’s <code>ActiveType</code> integration</p>
159
+ <p><a href="./doc/guide/virtual_models_md.html">Virtual models</a>: Unleashing non-persistent interactions through Compony’s <code>ActiveType</code> integration</p>
139
160
  </li></ul>
140
161
  </li><li>
141
162
  <p>Pre-built components shipped with Compony</p>
@@ -156,7 +177,7 @@
156
177
  </li><li>
157
178
  <p><a href="./doc/guide/pre_built_components/new_md.html">New</a>: Compony’s equivalent to Rail’s <code>new</code> and <code>create</code> controller action</p>
158
179
  </li><li>
159
- <p><a href="./doc/guide/pre_built_components/new_md.html">Edit</a>: Compony’s equivalent to Rail’s <code>edit</code> and <code>update</code> controller action</p>
180
+ <p><a href="./doc/guide/pre_built_components/edit_md.html">Edit</a>: Compony’s equivalent to Rail’s <code>edit</code> and <code>update</code> controller action</p>
160
181
  </li></ul>
161
182
  </li></ul>
162
183
 
@@ -199,7 +220,7 @@
199
220
  </div></div>
200
221
 
201
222
  <div id="footer">
202
- Generated on Fri May 15 10:29:33 2026 by
223
+ Generated on Mon May 18 13:55:32 2026 by
203
224
  <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
204
225
  0.9.34 (ruby-3.3.5).
205
226
  </div>
@@ -0,0 +1,314 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>
7
+ File: basic_component
8
+
9
+ &mdash; Documentation by YARD 0.9.34
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" />
16
+
17
+ <script type="text/javascript">
18
+ pathId = "basic_component";
19
+ relpath = '';
20
+ </script>
21
+
22
+
23
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
24
+
25
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
26
+
27
+
28
+ </head>
29
+ <body>
30
+ <div class="nav_wrap">
31
+ <iframe id="nav" src="file_list.html?1"></iframe>
32
+ <div id="resizer"></div>
33
+ </div>
34
+
35
+ <div id="main" tabindex="-1">
36
+ <div id="header">
37
+ <div id="menu">
38
+
39
+ <a href="_index.html">Index</a> &raquo;
40
+ <span class="title">File: basic_component</span>
41
+
42
+ </div>
43
+
44
+ <div id="search">
45
+
46
+ <a class="full_list_link" id="class_list_link"
47
+ href="class_list.html">
48
+
49
+ <svg width="24" height="24">
50
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
51
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
52
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
53
+ </svg>
54
+ </a>
55
+
56
+ </div>
57
+ <div class="clear"></div>
58
+ </div>
59
+
60
+ <div id="content"><div id='filecontents'>
61
+ <p><a href="/README_md.html#guide--documentation">Back to the guide</a></p>
62
+
63
+ <h1 id="label-What+is+a+component-3F">What is a component?</h1>
64
+
65
+ <p>Compony components are nestable elements that are capable of replacing Rails’ routes, views and controllers. They structure code for data manipulation, authentication and rendering into a single class that can easily be subclassed. This is achieved with Compony’s DSL that provides a readable and overridable way to store your logic.</p>
66
+
67
+ <p>Just like Rails, Compony is opinionated and you are advised to structure your code according to the examples and explanations. This makes it easier for others to dive into existing code.</p>
68
+
69
+ <h1 id="label-A+basic+-28bare-29+component">A basic (bare) component</h1>
70
+
71
+ <h2 id="label-Naming">Naming</h2>
72
+
73
+ <p>Compony components must be named according to the pattern <code>Components::FamilyName::ComponentName</code>.</p>
74
+ <ul><li>
75
+ <p>The family name should be pluralized and is analog to naming a Rails controller. For instance, when you would create a <code>UsersController</code> in plain Rails, the Compony family equivalent is <code>Users</code>.</p>
76
+ </li><li>
77
+ <p>The component name is the Compony analog to a Rails action.</p>
78
+ </li></ul>
79
+
80
+ <p>Example: If your plain Rails <code>UsersController</code> has an action <code>show</code>, the equivalent Compony component is <code>Components::Users::Show</code> and is located under <code>app/components/users/show.rb</code>.</p>
81
+
82
+ <p>If you have abstract components (i.e. components that your app never uses directly, but which you inherit from), you may name and place them arbitrarily.</p>
83
+
84
+ <h2 id="label-Initialization-2C+manual+instantiation+and+rendering">Initialization, manual instantiation and rendering</h2>
85
+
86
+ <p>You will rarely have to override <code>def initialize</code> of a component, as most of your code will go into the component’s <code>setup</code> block as explained below. However, when you do, make sure to forward all default arguments to the parent class, as they are essential to the component’s function:</p>
87
+
88
+ <pre class="code ruby"><code class="ruby"><span class='kw'>def</span> <span class='id identifier rubyid_initialize'>initialize</span><span class='lparen'>(</span><span class='id identifier rubyid_some_positional_argument'>some_positional_argument</span><span class='comma'>,</span> <span class='id identifier rubyid_another'>another</span><span class='op'>=</span><span class='kw'>nil</span><span class='comma'>,</span> <span class='op'>*</span><span class='id identifier rubyid_args'>args</span><span class='comma'>,</span> <span class='label'>some_keyword_argument:</span><span class='comma'>,</span> <span class='label'>yetanother:</span> <span class='int'>42</span><span class='comma'>,</span> <span class='op'>**</span><span class='id identifier rubyid_kwargs'>kwargs</span><span class='comma'>,</span> <span class='op'>&amp;</span><span class='id identifier rubyid_block'>block</span><span class='rparen'>)</span>
89
+ <span class='kw'>super</span><span class='lparen'>(</span><span class='op'>*</span><span class='id identifier rubyid_args'>args</span><span class='comma'>,</span> <span class='op'>**</span><span class='id identifier rubyid_kwargs'>kwargs</span><span class='comma'>,</span> <span class='op'>&amp;</span><span class='id identifier rubyid_block'>block</span><span class='rparen'>)</span> <span class='comment'># Typically you should call this first
90
+ </span> <span class='ivar'>@foo</span> <span class='op'>=</span> <span class='id identifier rubyid_some_positional_argument'>some_positional_argument</span>
91
+ <span class='ivar'>@bar</span> <span class='op'>=</span> <span class='id identifier rubyid_another'>another</span>
92
+ <span class='ivar'>@baz</span> <span class='op'>=</span> <span class='id identifier rubyid_some_keyword_argument'>some_keyword_argument</span>
93
+ <span class='ivar'>@stuff</span> <span class='op'>=</span> <span class='id identifier rubyid_yetanother'>yetanother</span>
94
+ <span class='kw'>end</span>
95
+ </code></pre>
96
+
97
+ <p>Typically, your components will be instantiated and rendered by Compony through the <a href="./standalone_md.html">“standalone” feature</a>. Nonetheless, it is possible to do so manually as well, for instance if you’d like to render a component from within an existing view in your application:</p>
98
+
99
+ <pre class="code ruby"><code class="ruby">&lt;% index_users_comp = Components::Users::Index.new %&gt;
100
+ &lt;%= index_users_comp.render(controller) %&gt;
101
+ </code></pre>
102
+
103
+ <p>Note that rendering a component always requires the controller as an argument. It also possible to pass an argument <code>locals</code> that will be made available to <code>render</code> (see below):</p>
104
+
105
+ <pre class="code ruby"><code class="ruby">&lt;% index_users_comp = Components::Users::Index.new %&gt;
106
+ &lt;%= index_users_comp.render(controller, locals: { weather: :sunny }) %&gt;
107
+ </code></pre>
108
+
109
+ <h2 id="label-Setup">Setup</h2>
110
+
111
+ <p>Every component must call the static method <code>setup</code> which will contain most of the code of your components. This can be achieved either by a call directly from your class, or by <a href="/doc/guide/inheritance_md.html">inheriting</a> from a component that calls <code>setup</code>. If both classes call the method, the inherited class’ <code>setup</code> is run first and the inheriting’s second, thus, the child class can override setup properties of the parent class.</p>
112
+
113
+ <p>Call setup as follows:</p>
114
+
115
+ <pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'><span class='object_link'><a href="Components.html" title="Components (module)">Components</a></span></span><span class='op'>::</span><span class='const'>Users</span><span class='op'>::</span><span class='const'>Show</span> <span class='op'>&lt;</span> <span class='const'><span class='object_link'><a href="Compony.html" title="Compony (module)">Compony</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Compony/Component.html" title="Compony::Component (class)">Component</a></span></span>
116
+ <span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
117
+ <span class='comment'># Your setup code goes here
118
+ </span> <span class='kw'>end</span>
119
+ <span class='kw'>end</span>
120
+ </code></pre>
121
+
122
+ <p>The code in setup is run at the end the component’s initialization. In this block, you will call a number of methods that define the component’s behavior and which we will explain now.</p>
123
+
124
+ <h3 id="label-Labelling">Labelling</h3>
125
+
126
+ <p>This defines a component’s label, both as seen from within the component and from the outside, e.g. from an <a href="/doc/guide/intents_md.html">intent</a>. You can query the label in order to display it as a title in your component. Links and buttons to components will also display the same label, allowing you to easily rename a component, including any parts of your UI that point to it.</p>
127
+
128
+ <p>Labels come in different formats, short and long, with long being the default. Define them as follows if your component is about a specific object, for instance a show component for a specific user:</p>
129
+
130
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
131
+ <span class='id identifier rubyid_label'>label</span><span class='lparen'>(</span><span class='symbol'>:short</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_user'>user</span><span class='op'>|</span> <span class='id identifier rubyid_user'>user</span><span class='period'>.</span><span class='id identifier rubyid_label'>label</span> <span class='rbrace'>}</span> <span class='comment'># Assuming your User model has a method or attribute `label`.
132
+ </span> <span class='id identifier rubyid_label'>label</span><span class='lparen'>(</span><span class='symbol'>:long</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_user'>user</span><span class='op'>|</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>Displaying user </span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_user'>user</span><span class='period'>.</span><span class='id identifier rubyid_label'>label</span><span class='embexpr_end'>}</span><span class='tstring_end'>&quot;</span></span> <span class='rbrace'>}</span> <span class='comment'># In practice, you&#39;d probably use I18n.t or FastGettext here to deal with translations.
133
+ </span>
134
+ <span class='comment'># Or use this short hand to set both long and short label to the user&#39;s label:
135
+ </span> <span class='id identifier rubyid_label'>label</span><span class='lparen'>(</span><span class='symbol'>:all</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_user'>user</span><span class='op'>|</span> <span class='id identifier rubyid_user'>user</span><span class='period'>.</span><span class='id identifier rubyid_label'>label</span> <span class='rbrace'>}</span>
136
+ <span class='kw'>end</span>
137
+ </code></pre>
138
+
139
+ <p>To read the label, from within the component or from outside, proceed as follows:</p>
140
+
141
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_label'>label</span><span class='lparen'>(</span><span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_first'>first</span><span class='rparen'>)</span> <span class='comment'># This returns the long version: &quot;Displaying user John Doe&quot;.
142
+ </span><span class='id identifier rubyid_label'>label</span><span class='lparen'>(</span><span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_first'>first</span><span class='comma'>,</span> <span class='label'>format:</span> <span class='symbol'>:short</span><span class='rparen'>)</span> <span class='comment'># This returns the short version &quot;John Doe&quot;.
143
+ </span></code></pre>
144
+
145
+ <p>It is important to note that since your label block takes an argument, you must provide the argument when reading the label. Only up to one argument is supported. Typically, label blocks of all <a href="/doc/guide/resourceful_md.html">resourceful components</a> take 1 argument while all others take 0.</p>
146
+
147
+ <p>Here is an example on how labelling looks like for a component that is not about a specific object, such as an index component for users:</p>
148
+
149
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
150
+ <span class='id identifier rubyid_label'>label</span><span class='lparen'>(</span><span class='symbol'>:long</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>List of users</span><span class='tstring_end'>&#39;</span></span> <span class='rbrace'>}</span>
151
+ <span class='id identifier rubyid_label'>label</span><span class='lparen'>(</span><span class='symbol'>:short</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>List</span><span class='tstring_end'>&#39;</span></span> <span class='rbrace'>}</span>
152
+ <span class='kw'>end</span>
153
+ </code></pre>
154
+
155
+ <p>And to read those:</p>
156
+
157
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_label'>label</span> <span class='comment'># &quot;List of users&quot;
158
+ </span><span class='id identifier rubyid_label'>label</span><span class='lparen'>(</span><span class='label'>format:</span> <span class='symbol'>:short</span><span class='rparen'>)</span> <span class='comment'># &quot;List&quot;
159
+ </span></code></pre>
160
+
161
+ <p>If you do not define any labels, Compony will fallback to the default which is using Rail’s <code>humanize</code> method to build a name from the family and component name, e.g. “index users”.</p>
162
+
163
+ <p>Additionally, components can specify an icon and a color. These are not used by Compony directly and it is up to you to to define how and where to use them. Example:</p>
164
+
165
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
166
+ <span class='id identifier rubyid_color'>color</span> <span class='lbrace'>{</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>#AA0000</span><span class='tstring_end'>&#39;</span></span> <span class='rbrace'>}</span>
167
+ <span class='id identifier rubyid_icon'>icon</span> <span class='lbrace'>{</span> <span class='qsymbols_beg'>%i[</span><span class='tstring_content'>fa-solid</span><span class='words_sep'> </span><span class='tstring_content'>circle</span><span class='tstring_end'>]</span></span> <span class='rbrace'>}</span>
168
+ <span class='kw'>end</span>
169
+ </code></pre>
170
+
171
+ <p>To retrieve them from outside the component, use:</p>
172
+
173
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_my_component'>my_component</span><span class='period'>.</span><span class='id identifier rubyid_color'>color</span> <span class='comment'># &#39;#AA0000&#39;
174
+ </span><span class='id identifier rubyid_my_component'>my_component</span><span class='period'>.</span><span class='id identifier rubyid_icon'>icon</span> <span class='comment'># [:&#39;fa-solid&#39;, :circle]
175
+ </span></code></pre>
176
+
177
+ <h3 id="label-Providing+content">Providing content</h3>
178
+
179
+ <p>Basic components do not come with default content. Instead, you must call the method <code>content</code> inside the setup block and provide a block containing your view. It will be evaluated inside a <a href="/doc/guide/internal_datastructures_md.html#requestcontext">request context</a>.</p>
180
+
181
+ <p>In this block, provide the HTML to be generated using Dyny: <a href="https://github.com/kalsan/dyny">github.com/kalsan/dyny</a></p>
182
+
183
+ <p>Here is an example of a component that renders a title along with a paragraph:</p>
184
+
185
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
186
+ <span class='id identifier rubyid_label'>label</span><span class='lparen'>(</span><span class='symbol'>:all</span><span class='rparen'>)</span> <span class='lbrace'>{</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Welcome</span><span class='tstring_end'>&#39;</span></span> <span class='rbrace'>}</span>
187
+ <span class='id identifier rubyid_content'>content</span> <span class='kw'>do</span>
188
+ <span class='id identifier rubyid_h1'>h1</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Welcome to my basic component.</span><span class='tstring_end'>&#39;</span></span>
189
+ <span class='id identifier rubyid_para'>para</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>It&#39;s not much, but it&#39;s honest work.</span><span class='tstring_end'>&quot;</span></span>
190
+ <span class='kw'>end</span>
191
+ <span class='kw'>end</span>
192
+ </code></pre>
193
+
194
+ <h4 id="label-Naming+content+blocks-2C+ordering+and+overriding+them+in+subclasses">Naming content blocks, ordering and overriding them in subclasses</h4>
195
+
196
+ <p>Content blocks are actually named. The <code>content</code> call adds or replaces a previously defined content block, e.g. in an earlier call to <code>setup</code> in a component’s superclass. When calling <code>content</code> without a name, it defaults to <code>main</code> and will overwrite any previous <code>main</code> content. However, you can provide your own name and refer to other names by using the <code>before:</code> keyword.</p>
197
+
198
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
199
+ <span class='id identifier rubyid_content'>content</span> <span class='kw'>do</span> <span class='comment'># will become :main
200
+ </span> <span class='id identifier rubyid_h1'>h1</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Welcome to my basic component.</span><span class='tstring_end'>&#39;</span></span>
201
+ <span class='kw'>end</span>
202
+ <span class='id identifier rubyid_content'>content</span> <span class='symbol'>:thanks</span> <span class='kw'>do</span>
203
+ <span class='id identifier rubyid_para'>para</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Thank you and see you tomorrow.</span><span class='tstring_end'>&#39;</span></span>
204
+ <span class='kw'>end</span>
205
+ <span class='id identifier rubyid_content'>content</span> <span class='symbol'>:middle</span><span class='comma'>,</span> <span class='label'>before:</span> <span class='symbol'>:thanks</span> <span class='kw'>do</span>
206
+ <span class='id identifier rubyid_para'>para</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>This paragraph is inserted between the others.</span><span class='tstring_end'>&#39;</span></span>
207
+ <span class='kw'>end</span>
208
+ <span class='id identifier rubyid_content'>content</span> <span class='symbol'>:thanks</span> <span class='kw'>do</span>
209
+ <span class='id identifier rubyid_para'>para</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Thank you and see you tonight.</span><span class='tstring_end'>&#39;</span></span> <span class='comment'># this overwrites &quot;Thank you and see you tomorrow.&quot;
210
+ </span> <span class='kw'>end</span>
211
+ <span class='id identifier rubyid_content'>content</span> <span class='symbol'>:first</span><span class='comma'>,</span> <span class='label'>before:</span> <span class='symbol'>:main</span> <span class='kw'>do</span>
212
+ <span class='id identifier rubyid_para'>para</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>This appears first.</span><span class='tstring_end'>&#39;</span></span>
213
+ <span class='kw'>end</span>
214
+ <span class='kw'>end</span>
215
+ </code></pre>
216
+
217
+ <p>This results in: - This appears first. - Welcome to my basic component. - This paragraph is inserted between the others. - Thank you and see you tonight.</p>
218
+
219
+ <p>As you see, overusing this feature can lead to messy code as it becomes unclear what happens in what order. For this reason, this feature should only be used to decouple the content of your abstract components for allowing surgical overrides in <a href="/doc/guide/inheritance_md.html">subclasses</a>.</p>
220
+
221
+ <p>It is a good convention to always have one content block named <code>:main</code>, as you might want to refer to it in subclasses.</p>
222
+
223
+ <h4 id="label-Nesting+content+blocks-2C+calling+a+content+block+from+another">Nesting content blocks, calling a content block from another</h4>
224
+
225
+ <p>In some situations, such as in forms, it can be useful to nest content blocks. This will also allow subclasses to override a wrapper while keeping the content, and vice versa. To make this possible, you can also use the <code>content</code> keyword inside a content block. Note that unlike the call in <code>setup</code>, this call will render a content block instead of defining it. This happens inside the request context and the content block must be defined inside the current component.</p>
226
+
227
+ <p>Note that you cannot call another component’s content block this way.</p>
228
+
229
+ <p>Here is an example on how to use this feature, e.g. to create a bootstrap card that can be overridden with precision:</p>
230
+
231
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Components::Bootstrap::Card
232
+ </span><span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
233
+ <span class='id identifier rubyid_content'>content</span> <span class='label'>hidden:</span> <span class='kw'>true</span> <span class='kw'>do</span> <span class='comment'># hidden: true will cause `render` to skip this content block. You can still use it in the nested fashion.
234
+ </span> <span class='id identifier rubyid_div'>div</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>I am the default content for the card</span><span class='tstring_end'>&#39;</span></span>
235
+ <span class='kw'>end</span>
236
+
237
+ <span class='id identifier rubyid_content'>content</span> <span class='symbol'>:card</span> <span class='kw'>do</span>
238
+ <span class='id identifier rubyid_div'>div</span> <span class='label'>class:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>card card-body</span><span class='tstring_end'>&#39;</span></span> <span class='kw'>do</span>
239
+ <span class='id identifier rubyid_content'>content</span> <span class='symbol'>:main</span>
240
+ <span class='kw'>end</span>
241
+ <span class='kw'>end</span>
242
+ <span class='kw'>end</span>
243
+ </code></pre>
244
+
245
+ <p>The output is:</p>
246
+
247
+ <pre class="code ruby"><code class="ruby">&lt;div class=&quot;card card-body&quot;&gt;&lt;div&gt;I am the default content for the card&lt;/div&gt;&lt;/div&gt;
248
+ </code></pre>
249
+
250
+ <p>So when you subclass this component, you can forget about the card and just overwrite <code>:main</code> as follows:</p>
251
+
252
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Components::Hello::HelloCard &lt; Components::Bootstrap::Card
253
+ </span><span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
254
+ <span class='id identifier rubyid_content'>content</span> <span class='kw'>do</span> <span class='comment'># hidden is still true because the old :main content block specified that already.
255
+ </span> <span class='id identifier rubyid_h1'>h1</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Hello</span><span class='tstring_end'>&#39;</span></span>
256
+ <span class='id identifier rubyid_para'>para</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Welcome to my site.</span><span class='tstring_end'>&#39;</span></span>
257
+ <span class='kw'>end</span>
258
+ <span class='kw'>end</span>
259
+ </code></pre>
260
+
261
+ <p>The output is:</p>
262
+
263
+ <pre class="code ruby"><code class="ruby">&lt;div class=&quot;card card-body&quot;&gt;&lt;h1&gt;Hello&lt;/h1&gt;&lt;p&gt;Welcome to my site.&lt;/p&gt;&lt;/div&gt;
264
+ </code></pre>
265
+
266
+ <h4 id="label-Removing+content+blocks">Removing content blocks</h4>
267
+
268
+ <p>If a component’s parent class defines a content block that is undesired in a subclass component, the content block can be removed as follows:</p>
269
+
270
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
271
+ <span class='id identifier rubyid_remove_content'>remove_content</span> <span class='symbol'>:some_content_defined_in_parent</span> <span class='comment'># This component will now behave as if this content block was never declared in its parent.
272
+ </span><span class='kw'>end</span>
273
+ </code></pre>
274
+
275
+ <h3 id="label-Redirecting+away+-2F+Intercepting+rendering">Redirecting away / Intercepting rendering</h3>
276
+
277
+ <p>Immediately before the <code>content</code> block(s) are evaluated, another chain of blocks is evaluated if present: <code>before_render</code>. If on of these blocks creates a reponse body in the Rails controller, the subsequent <code>before_render</code> blocks and all <code>content</code> blocks are skipped.</p>
278
+
279
+ <p>This is useful for redirecting. Here is an example of a component that provides a restaurant’s lunch menu, but redirects to the menu overview page instead if it’s not lunch time:</p>
280
+
281
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
282
+ <span class='id identifier rubyid_label'>label</span><span class='lparen'>(</span><span class='symbol'>:all</span><span class='rparen'>)</span><span class='lbrace'>{</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Lunch menu</span><span class='tstring_end'>&#39;</span></span> <span class='rbrace'>}</span>
283
+
284
+ <span class='id identifier rubyid_before_render'>before_render</span> <span class='kw'>do</span>
285
+ <span class='id identifier rubyid_current_time'>current_time</span> <span class='op'>=</span> <span class='const'>Time</span><span class='period'>.</span><span class='id identifier rubyid_zone'>zone</span><span class='period'>.</span><span class='id identifier rubyid_now'>now</span>
286
+ <span class='kw'>if</span> <span class='id identifier rubyid_current_time'>current_time</span><span class='period'>.</span><span class='id identifier rubyid_hour'>hour</span> <span class='op'>&gt;=</span> <span class='int'>11</span> <span class='op'>&amp;&amp;</span> <span class='id identifier rubyid_current_time'>current_time</span><span class='period'>.</span><span class='id identifier rubyid_hour'>hour</span> <span class='op'>&lt;</span> <span class='int'>14</span>
287
+ <span class='id identifier rubyid_flash'>flash</span><span class='period'>.</span><span class='id identifier rubyid_notice'>notice</span> <span class='op'>=</span> <span class='tstring'><span class='tstring_beg'>&quot;</span><span class='tstring_content'>Sorry, it&#39;s not lunch time.</span><span class='tstring_end'>&quot;</span></span>
288
+ <span class='id identifier rubyid_redirect_to'>redirect_to</span> <span class='const'><span class='object_link'><a href="Compony.html" title="Compony (module)">Compony</a></span></span><span class='period'>.</span><span class='id identifier rubyid_path'><span class='object_link'><a href="Compony.html#path-class_method" title="Compony.path (method)">path</a></span></span><span class='lparen'>(</span><span class='symbol'>:index</span><span class='comma'>,</span> <span class='symbol'>:menus</span><span class='rparen'>)</span>
289
+ <span class='kw'>end</span>
290
+ <span class='kw'>end</span>
291
+
292
+ <span class='id identifier rubyid_content'>content</span> <span class='kw'>do</span> <span class='comment'># This is entirely skipped if it&#39;s not lunch time.
293
+ </span> <span class='id identifier rubyid_h1'>h1</span> <span class='id identifier rubyid_label'>label</span>
294
+ <span class='id identifier rubyid_para'>para</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Today we have spaghetti.</span><span class='tstring_end'>&#39;</span></span>
295
+ <span class='kw'>end</span>
296
+ <span class='kw'>end</span>
297
+ </code></pre>
298
+
299
+ <p>Note how Compony’s <a href="/doc/guide/intents_md.html#componypath">path helper</a> is used to generate the path. This is the recommended approach to redirecting to a component.</p>
300
+
301
+ <p>Similarly to <code>content</code>, the <code>before_render</code> method also accepts a name, defaulting to <code>:main</code>, as well as a <code>before:</code> keyword. This allows you to selectively extend and/or override <code>before_render</code> blocks in subclasses.</p>
302
+
303
+ <p><a href="/README_md.html#guide--documentation">Guide index</a></p>
304
+ </div></div>
305
+
306
+ <div id="footer">
307
+ Generated on Mon May 18 13:55:33 2026 by
308
+ <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
309
+ 0.9.34 (ruby-3.3.5).
310
+ </div>
311
+
312
+ </div>
313
+ </body>
314
+ </html>
@@ -0,0 +1,189 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>
7
+ File: cookbook
8
+
9
+ &mdash; Documentation by YARD 0.9.34
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" />
16
+
17
+ <script type="text/javascript">
18
+ pathId = "cookbook";
19
+ relpath = '';
20
+ </script>
21
+
22
+
23
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
24
+
25
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
26
+
27
+
28
+ </head>
29
+ <body>
30
+ <div class="nav_wrap">
31
+ <iframe id="nav" src="file_list.html?1"></iframe>
32
+ <div id="resizer"></div>
33
+ </div>
34
+
35
+ <div id="main" tabindex="-1">
36
+ <div id="header">
37
+ <div id="menu">
38
+
39
+ <a href="_index.html">Index</a> &raquo;
40
+ <span class="title">File: cookbook</span>
41
+
42
+ </div>
43
+
44
+ <div id="search">
45
+
46
+ <a class="full_list_link" id="class_list_link"
47
+ href="class_list.html">
48
+
49
+ <svg width="24" height="24">
50
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
51
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
52
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
53
+ </svg>
54
+ </a>
55
+
56
+ </div>
57
+ <div class="clear"></div>
58
+ </div>
59
+
60
+ <div id="content"><div id='filecontents'>
61
+ <p><a href="/README_md.html#guide--documentation">Back to the guide</a></p>
62
+
63
+ <h1 id="label-Cookbook">Cookbook</h1>
64
+
65
+ <p>Task-oriented entry point: “I want to do X — where is it?”. Every recipe lives in <a href="./patterns_md.html">Real-world patterns</a> or the guide; this page is a pure index by goal so you don’t need to know a pattern’s name. Nothing is duplicated here — only links.</p>
66
+
67
+ <h2 id="label-Recipes+by+task">Recipes by task</h2>
68
+
69
+ <table role="table">
70
+ <thead>
71
+ <tr>
72
+ <th>I want to…</th>
73
+ <th>See</th>
74
+ </tr>
75
+ </thead>
76
+ <tbody>
77
+ <tr>
78
+ <td>Share layout/chrome across all components</td>
79
+ <td>[patterns §1 base layer](./patterns.md#1-the-app-base-component-layer)</td>
80
+ </tr>
81
+ <tr>
82
+ <td>Add a CRUD screen with almost no code</td>
83
+ <td>[patterns §2 thin leaves](./patterns.md#2-thin-leaf-components), [example.md](./example.md)</td>
84
+ </tr>
85
+ <tr>
86
+ <td>List records with columns/filters/sorts</td>
87
+ <td>[List](./pre_built_components/list.md), [patterns §3–4](./patterns.md#3-index–load_data-scope–nested-list)</td>
88
+ </tr>
89
+ <tr>
90
+ <td>Scope/order what an Index shows</td>
91
+ <td>[patterns §3](./patterns.md#3-index–load_data-scope–nested-list) (‘load_data`)</td>
92
+ </tr>
93
+ <tr>
94
+ <td>Embed a child list inside a Show</td>
95
+ <td>[patterns §4](./patterns.md#4-list-customization), [nesting.md](./nesting.md)</td>
96
+ </tr>
97
+ <tr>
98
+ <td>Build a custom form + strong params</td>
99
+ <td>[patterns §5](./patterns.md#5-custom-form–schemacop-kept-in-sync), [Form](./pre_built_components/form.md)</td>
100
+ </tr>
101
+ <tr>
102
+ <td>Nested attributes in a form</td>
103
+ <td>[patterns §5](./patterns.md#5-custom-form–schemacop-kept-in-sync), [example_advanced.md](./example_advanced.md)</td>
104
+ </tr>
105
+ <tr>
106
+ <td>Autocomplete / ajax select field</td>
107
+ <td>[patterns §6](./patterns.md#6-autocomplete-form-app-level-subclass)</td>
108
+ </tr>
109
+ <tr>
110
+ <td>Split a detail page into tabs</td>
111
+ <td>[patterns §7](./patterns.md#7-tabbed-show-via-a-mixin)</td>
112
+ </tr>
113
+ <tr>
114
+ <td>Prefill/derive fields before save</td>
115
+ <td>[patterns §8](./patterns.md#8-lifecycle-hooks-for-derived-data) (‘after_assign_attributes`)</td>
116
+ </tr>
117
+ <tr>
118
+ <td>Guard/redirect before rendering</td>
119
+ <td>[patterns §8](./patterns.md#8-lifecycle-hooks-for-derived-data), [basic_component.md](./basic_component.md#redirecting-away–intercepting-rendering)</td>
120
+ </tr>
121
+ <tr>
122
+ <td>Customize the action toolbar</td>
123
+ <td>[patterns §9](./patterns.md#9-exposed-intents-as-the-action-toolbar), [intents.md](./intents.md#exposed-intents)</td>
124
+ </tr>
125
+ <tr>
126
+ <td>Disable a button with a reason</td>
127
+ <td>[feasibility.md](./feasibility.md), [patterns §9](./patterns.md#9-exposed-intents-as-the-action-toolbar)</td>
128
+ </tr>
129
+ <tr>
130
+ <td>Export CSV / PDF</td>
131
+ <td>[patterns §10](./patterns.md#10-csv–pdf-via-respond-format)</td>
132
+ </tr>
133
+ <tr>
134
+ <td>Launch a background job from a button</td>
135
+ <td>[patterns §11](./patterns.md#11-non-crud-job-dispatch-toggles-clone)</td>
136
+ </tr>
137
+ <tr>
138
+ <td>Toggle a boolean (activate/lock/…)</td>
139
+ <td>[patterns §11](./patterns.md#11-non-crud-job-dispatch-toggles-clone)</td>
140
+ </tr>
141
+ <tr>
142
+ <td>Clone/duplicate a record</td>
143
+ <td>[patterns §11](./patterns.md#11-non-crud-job-dispatch-toggles-clone)</td>
144
+ </tr>
145
+ <tr>
146
+ <td>Non-persistent / upload-only form</td>
147
+ <td>[patterns §12](./patterns.md#12-virtual-model-for-non-persistent–upload-forms), [virtual_models.md](./virtual_models.md)</td>
148
+ </tr>
149
+ <tr>
150
+ <td>Public page / inbound webhook</td>
151
+ <td>[patterns §13](./patterns.md#13-public-endpoints–webhooks), [gotchas §14](./gotchas.md#14-public-endpoint-still-401redirecting)</td>
152
+ </tr>
153
+ <tr>
154
+ <td>Custom button look</td>
155
+ <td>[patterns §14](./patterns.md#14-custom-button-style), [intents.md](./intents.md#adding-your-own-styles)</td>
156
+ </tr>
157
+ <tr>
158
+ <td>Inline-edit a card without a full page</td>
159
+ <td>[patterns §15 turbo-frame inline edit](./patterns.md#15-inline-edit-card-with-a-turbo-frame)</td>
160
+ </tr>
161
+ <tr>
162
+ <td>Multi-step wizard across components</td>
163
+ <td>[patterns §16 multi-step wizard](./patterns.md#16-multi-step-wizard-across-components)</td>
164
+ </tr>
165
+ <tr>
166
+ <td>Reorder/inline-patch without a form</td>
167
+ <td>[patterns §17 inline PATCH](./patterns.md#17-inline-patch-without-a-form-reorder–quick-toggle)</td>
168
+ </tr>
169
+ <tr>
170
+ <td>Magic-login / invite / reset / confirm link (no session)</td>
171
+ <td>[patterns §18 signed-token capability links](./patterns.md#18-signed-token-capability-links-auth-less-onboarding–magic-links)</td>
172
+ </tr>
173
+ </tbody>
174
+ </table>
175
+
176
+ <p>If a goal isn’t listed, check the <a href="./dsl_reference_md.html">DSL reference</a> and <a href="./glossary_md.html">glossary</a>.</p>
177
+
178
+ <p><a href="/README_md.html#guide--documentation">Guide index</a></p>
179
+ </div></div>
180
+
181
+ <div id="footer">
182
+ Generated on Mon May 18 13:55:34 2026 by
183
+ <a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
184
+ 0.9.34 (ruby-3.3.5).
185
+ </div>
186
+
187
+ </div>
188
+ </body>
189
+ </html>