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.
- checksums.yaml +4 -4
- data/.yardopts +36 -1
- data/CHANGELOG.md +31 -0
- data/CLAUDE.md +85 -0
- data/Gemfile.lock +1 -1
- data/README.md +13 -3
- data/VERSION +1 -1
- data/compony.gemspec +3 -3
- data/doc/ComponentGenerator.html +1 -1
- data/doc/Components.html +1 -1
- data/doc/ComponentsGenerator.html +1 -1
- data/doc/Compony/Component.html +54 -54
- data/doc/Compony/ComponentMixins/Default/Labelling.html +1 -1
- data/doc/Compony/ComponentMixins/Default/Standalone/ResourcefulVerbDsl.html +1 -1
- data/doc/Compony/ComponentMixins/Default/Standalone/StandaloneDsl.html +109 -70
- data/doc/Compony/ComponentMixins/Default/Standalone/VerbDsl.html +64 -28
- data/doc/Compony/ComponentMixins/Default/Standalone.html +1 -1
- data/doc/Compony/ComponentMixins/Default.html +1 -1
- data/doc/Compony/ComponentMixins/Resourceful.html +213 -74
- data/doc/Compony/ComponentMixins.html +1 -1
- data/doc/Compony/Components/Buttons/CssButton.html +1 -1
- data/doc/Compony/Components/Buttons/Link.html +1 -1
- data/doc/Compony/Components/Buttons.html +1 -1
- data/doc/Compony/Components/Destroy.html +83 -29
- data/doc/Compony/Components/Edit.html +110 -38
- data/doc/Compony/Components/Form.html +551 -208
- data/doc/Compony/Components/Index.html +1 -1
- data/doc/Compony/Components/List.html +3 -3
- data/doc/Compony/Components/New.html +110 -38
- data/doc/Compony/Components/Show.html +1 -1
- data/doc/Compony/Components/WithForm.html +194 -47
- data/doc/Compony/Components.html +1 -1
- data/doc/Compony/ControllerMixin.html +1 -1
- data/doc/Compony/Engine.html +1 -1
- data/doc/Compony/Intent.html +2 -2
- data/doc/Compony/ManageIntentsDsl.html +1 -1
- data/doc/Compony/MethodAccessibleHash.html +1 -1
- data/doc/Compony/ModelFields/Anchormodel.html +1 -1
- data/doc/Compony/ModelFields/Association.html +1 -1
- data/doc/Compony/ModelFields/Attachment.html +1 -1
- data/doc/Compony/ModelFields/Base.html +1 -1
- data/doc/Compony/ModelFields/Boolean.html +1 -1
- data/doc/Compony/ModelFields/Color.html +1 -1
- data/doc/Compony/ModelFields/Currency.html +1 -1
- data/doc/Compony/ModelFields/Date.html +1 -1
- data/doc/Compony/ModelFields/Datetime.html +1 -1
- data/doc/Compony/ModelFields/Decimal.html +1 -1
- data/doc/Compony/ModelFields/Email.html +1 -1
- data/doc/Compony/ModelFields/Float.html +1 -1
- data/doc/Compony/ModelFields/Integer.html +1 -1
- data/doc/Compony/ModelFields/Percentage.html +1 -1
- data/doc/Compony/ModelFields/Phone.html +1 -1
- data/doc/Compony/ModelFields/RichText.html +1 -1
- data/doc/Compony/ModelFields/String.html +1 -1
- data/doc/Compony/ModelFields/Text.html +1 -1
- data/doc/Compony/ModelFields/Time.html +1 -1
- data/doc/Compony/ModelFields/Url.html +1 -1
- data/doc/Compony/ModelFields.html +1 -1
- data/doc/Compony/ModelMixin.html +1 -1
- data/doc/Compony/NaturalOrdering.html +1 -1
- data/doc/Compony/RequestContext.html +1 -1
- data/doc/Compony/Version.html +1 -1
- data/doc/Compony/ViewHelpers.html +1 -1
- data/doc/Compony/VirtualModel.html +1 -1
- data/doc/Compony.html +1 -1
- data/doc/ComponyController.html +1 -1
- data/doc/_index.html +97 -1
- data/doc/file.CHANGELOG.html +758 -0
- data/doc/file.README.html +25 -4
- data/doc/file.basic_component.html +314 -0
- data/doc/file.cookbook.html +189 -0
- data/doc/file.destroy.html +105 -0
- data/doc/file.dsl_reference.html +672 -0
- data/doc/file.edit.html +109 -0
- data/doc/file.example.html +291 -0
- data/doc/file.example_advanced.html +257 -0
- data/doc/file.feasibility.html +115 -0
- data/doc/file.form.html +195 -0
- data/doc/file.generators.html +89 -0
- data/doc/file.glossary.html +217 -0
- data/doc/file.gotchas.html +222 -0
- data/doc/file.index.html +135 -0
- data/doc/file.inheritance.html +136 -0
- data/doc/file.installation.html +115 -0
- data/doc/file.integrations.html +218 -0
- data/doc/file.intents.html +265 -0
- data/doc/file.internal_datastructures.html +129 -0
- data/doc/file.list.html +253 -0
- data/doc/file.maintaining.html +127 -0
- data/doc/file.model_fields.html +137 -0
- data/doc/file.nesting.html +237 -0
- data/doc/file.new.html +109 -0
- data/doc/file.ownership.html +98 -0
- data/doc/file.patterns.html +669 -0
- data/doc/file.pre_built_components.html +99 -0
- data/doc/file.resourceful.html +181 -0
- data/doc/file.show.html +158 -0
- data/doc/file.standalone.html +233 -0
- data/doc/file.virtual_models.html +117 -0
- data/doc/file.with_form.html +157 -0
- data/doc/file_list.html +160 -0
- data/doc/guide/cookbook.md +41 -0
- data/doc/guide/dsl_reference.md +155 -0
- data/doc/guide/example_advanced.md +209 -0
- data/doc/guide/generators.md +1 -1
- data/doc/guide/glossary.md +42 -0
- data/doc/guide/gotchas.md +125 -0
- data/doc/guide/maintaining.md +64 -0
- data/doc/guide/patterns.md +681 -0
- data/doc/guide/pre_built_components/edit.md +1 -1
- data/doc/guide/pre_built_components/index.md +64 -1
- data/doc/guide/pre_built_components/list.md +111 -7
- data/doc/guide/pre_built_components/show.md +57 -2
- data/doc/guide/pre_built_components/with_form.md +56 -9
- data/doc/guide/pre_built_components.md +7 -2
- data/doc/guide/standalone.md +16 -1
- data/doc/index.html +25 -4
- data/doc/integrations.md +61 -0
- data/doc/llms.txt +62 -0
- data/doc/top-level-namespace.html +1 -1
- data/lib/compony/component.rb +8 -3
- data/lib/compony/component_mixins/default/standalone/standalone_dsl.rb +32 -15
- data/lib/compony/component_mixins/default/standalone/verb_dsl.rb +11 -3
- data/lib/compony/component_mixins/resourceful.rb +30 -16
- data/lib/compony/components/destroy.rb +21 -1
- data/lib/compony/components/edit.rb +25 -1
- data/lib/compony/components/form.rb +63 -21
- data/lib/compony/components/list.rb +1 -1
- data/lib/compony/components/new.rb +25 -1
- data/lib/compony/components/with_form.rb +20 -5
- data/lib/compony/intent.rb +1 -1
- metadata +43 -1
data/doc/file.edit.html
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
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: edit
|
|
8
|
+
|
|
9
|
+
— 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 = "edit";
|
|
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> »
|
|
40
|
+
<span class="title">File: edit</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'><ul><li>
|
|
61
|
+
<p><a href="/README_md.html#guide--documentation">Back to the guide</a></p>
|
|
62
|
+
</li><li>
|
|
63
|
+
<p><a href="/doc/guide/pre_built_components_md.html">List of pre-built components</a></p>
|
|
64
|
+
</li></ul>
|
|
65
|
+
|
|
66
|
+
<h1 id="label-Pre-built+components-3A+Edit">Pre-built components: Edit</h1>
|
|
67
|
+
|
|
68
|
+
<p>This component is the Compony equivalent to a typical Rails controller’s <code>edit</code> and <code>update</code> actions.</p>
|
|
69
|
+
|
|
70
|
+
<p><code>Compony::Components::Edit</code> is a resourceful standalone component based on href="./with_form_md.html"></a> that listens to two verbs:</p>
|
|
71
|
+
<ul><li>
|
|
72
|
+
<p>GET will cause the Edit component to load a record given by ID and render the form based on that record. If the record does not exist, a HTTP 404 code is returned.</p>
|
|
73
|
+
</li><li>
|
|
74
|
+
<p>PATCH (equivalent to a <code>update</code> action in a controller) will attempt to save the resource. If that fails, the form is rendered again with a HTTP 422 code (“unprocessable entity”). If the update succeeds, a flash is shown and the user is redirected:</p>
|
|
75
|
+
</li><li>
|
|
76
|
+
<p>if present: the data’s Show component</p>
|
|
77
|
+
</li><li>
|
|
78
|
+
<p>otherwise, if the resource is owned by another resource class: the owner’s Show component</p>
|
|
79
|
+
</li><li>
|
|
80
|
+
<p>otherwise, the data’s Index component</p>
|
|
81
|
+
</li></ul>
|
|
82
|
+
|
|
83
|
+
<p>Unlike in New and Destroy, Edit’s authorization checks for <code>edit</code> in GET and for <code>update</code> in PATCH. This enables you to “abuse” an Edit component to double as a Show component. Users having only <code>:read</code> permission will not see any links or buttons pointing to an Edit component. Users having only <code>:edit</code> permissions can see the form (including the data) but not submit it. Users having <code>:write</code> permissions can edit and update the Resource, in accordance to CanCanCan’s <code>:write</code> alias.</p>
|
|
84
|
+
|
|
85
|
+
<p>This component follows the <a href="/doc/guide/resourceful_md.html#complete-resourceful-lifecycle">resourceful lifecycle</a>. Parameters are validated in <code>assign_attributes</code> using a Schemacop schema that is generated from the form. The schema corresponds to Rail’s typical strong parameter structure for forms. For example, a user’s Edit component would look for a parameter <code>user</code> holding a hash of attributes (e.g. <code>user[first_name]=Tom</code>).</p>
|
|
86
|
+
|
|
87
|
+
<p>In case you overwrite <code>store_data</code>, make sure to set <code>@update_succeeded</code> to true if storing was successful (and to set it to false otherwise).</p>
|
|
88
|
+
|
|
89
|
+
<p>The following DSL calls are implemented to allow for convenient overrides of default logic:</p>
|
|
90
|
+
<ul><li>
|
|
91
|
+
<p>The block <code>on_update_failed</code> is run if <code>@update_succeeded</code> is not true. By default, it logs all error messages with level <code>warn</code> and renders the component again through HTTP 422, causing Turbo to correctly display the page. Error messages are displayed by the form inputs.</p>
|
|
92
|
+
</li><li>
|
|
93
|
+
<p>The block <code>on_updated</code> is evaluated between successful record creation and responding. By default, it is not implemented and doing so is optional. This would be a suitable location for hooks that update state after a resource was updated (like an <code>after_update</code> hook, but only executed if a record was updated by this component). Do not redirect or render here, use the next blocks instead.</p>
|
|
94
|
+
</li><li>
|
|
95
|
+
<p>The block given in <code>on_updated_respond</code> is evaluated after successful creation and by default shows a flash, then redirects. Overwrite this block if you need to completely customize all logic that happens after creation. If this block is overwritten, <code>on_updated_redirect_path</code> will not be called.</p>
|
|
96
|
+
</li><li>
|
|
97
|
+
<p><code>on_updated_redirect_path</code> is evaluated as the second step of <code>on_updated_respond</code> and redirects to the resource’s Show, its owner’s Show, or its own Index component as described above. Overwrite this block in order to redirect ot another component instead, while keeping the default flash provided by <code>on_updated_respond</code>.</p>
|
|
98
|
+
</li></ul>
|
|
99
|
+
</div></div>
|
|
100
|
+
|
|
101
|
+
<div id="footer">
|
|
102
|
+
Generated on Mon May 18 13:55:34 2026 by
|
|
103
|
+
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
104
|
+
0.9.34 (ruby-3.3.5).
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
</div>
|
|
108
|
+
</body>
|
|
109
|
+
</html>
|
|
@@ -0,0 +1,291 @@
|
|
|
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: example
|
|
8
|
+
|
|
9
|
+
— 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 = "example";
|
|
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> »
|
|
40
|
+
<span class="title">File: example</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-Example">Example</h1>
|
|
64
|
+
|
|
65
|
+
<p>To get you a rough idea what working with Compony feels like, let’s look at a small dummy application using Compony from scratch, to make this example as explicit as possible. In practice, much of the logic shown here would be moved to abstract components that you can inherit from.</p>
|
|
66
|
+
|
|
67
|
+
<p>The example is meant to be read top-down and information will mostly not be repeated. Comments will give you a rough idea of what’s going on on each line. The features are more completely documented in subsequent chapters.</p>
|
|
68
|
+
|
|
69
|
+
<p>Please note that from this example alone, you won’t be able to comprehend the underlying concepts - refer to the rest of the <a href="/README_md.html#guide--documentation">guide</a> for this.</p>
|
|
70
|
+
|
|
71
|
+
<p>Let’s implement a simple user management page with Compony. User’s have a name, an integer age, a comment, as well as a role (which we will conveniently model using <code>AnchorModel</code>: <a href="https://github.com/kalsan/anchormodel">github.com/kalsan/anchormodel</a>). We want to be able to list, show, create, edit and destroy users. Users having the role Admin shall not be destroyed.</p>
|
|
72
|
+
|
|
73
|
+
<h2 id="label-The+User+model">The User model</h2>
|
|
74
|
+
|
|
75
|
+
<p>We’ll assume a model that has the standard Rails schema:</p>
|
|
76
|
+
|
|
77
|
+
<pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_create_table'>create_table</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>users</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>force:</span> <span class='symbol'>:cascade</span> <span class='kw'>do</span> <span class='op'>|</span><span class='id identifier rubyid_t'>t</span><span class='op'>|</span>
|
|
78
|
+
<span class='id identifier rubyid_t'>t</span><span class='period'>.</span><span class='id identifier rubyid_string'>string</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>name</span><span class='tstring_end'>'</span></span>
|
|
79
|
+
<span class='id identifier rubyid_t'>t</span><span class='period'>.</span><span class='id identifier rubyid_string'>string</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>comment</span><span class='tstring_end'>'</span></span>
|
|
80
|
+
<span class='id identifier rubyid_t'>t</span><span class='period'>.</span><span class='id identifier rubyid_integer'>integer</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>age</span><span class='tstring_end'>'</span></span>
|
|
81
|
+
<span class='id identifier rubyid_t'>t</span><span class='period'>.</span><span class='id identifier rubyid_datetime'>datetime</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>created_at</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>null:</span> <span class='kw'>false</span>
|
|
82
|
+
<span class='id identifier rubyid_t'>t</span><span class='period'>.</span><span class='id identifier rubyid_datetime'>datetime</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>updated_at</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>null:</span> <span class='kw'>false</span>
|
|
83
|
+
<span class='id identifier rubyid_t'>t</span><span class='period'>.</span><span class='id identifier rubyid_string'>string</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>role</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>default:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>guest</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>null:</span> <span class='kw'>false</span>
|
|
84
|
+
<span class='kw'>end</span>
|
|
85
|
+
</code></pre>
|
|
86
|
+
|
|
87
|
+
<pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>User</span> <span class='op'><</span> <span class='const'>ApplicationRecord</span>
|
|
88
|
+
<span class='comment'># Refer to https://github.com/kalsan/anchormodel
|
|
89
|
+
</span> <span class='id identifier rubyid_belongs_to_anchormodel'>belongs_to_anchormodel</span> <span class='symbol'>:role</span>
|
|
90
|
+
|
|
91
|
+
<span class='comment'># Fields define which attributes are relevant in the GUI and how they should be presented.
|
|
92
|
+
</span> <span class='id identifier rubyid_field'>field</span> <span class='symbol'>:name</span><span class='comma'>,</span> <span class='symbol'>:string</span>
|
|
93
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:age</span><span class='comma'>,</span> <span class='symbol'>:integer</span>
|
|
94
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:comment</span><span class='comma'>,</span> <span class='symbol'>:string</span>
|
|
95
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:role</span><span class='comma'>,</span> <span class='symbol'>:anchormodel</span>
|
|
96
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:created_at</span><span class='comma'>,</span> <span class='symbol'>:datetime</span>
|
|
97
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:updated_at</span><span class='comma'>,</span> <span class='symbol'>:datetime</span>
|
|
98
|
+
|
|
99
|
+
<span class='comment'># The method `label` must be implemented on all Compony models. Instead of this method, we could also rename the column :name to :label.
|
|
100
|
+
</span> <span class='kw'>def</span> <span class='id identifier rubyid_label'>label</span>
|
|
101
|
+
<span class='id identifier rubyid_name'>name</span>
|
|
102
|
+
<span class='kw'>end</span>
|
|
103
|
+
|
|
104
|
+
<span class='comment'># This is how we tell Compony that admins are not to be destroyed.
|
|
105
|
+
</span> <span class='id identifier rubyid_prevent'>prevent</span> <span class='symbol'>:destroy</span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Cannot destroy admins</span><span class='tstring_end'>'</span></span> <span class='kw'>do</span>
|
|
106
|
+
<span class='id identifier rubyid_role'>role</span> <span class='op'>==</span> <span class='const'>Role</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span><span class='lparen'>(</span><span class='symbol'>:admin</span><span class='rparen'>)</span>
|
|
107
|
+
<span class='kw'>end</span>
|
|
108
|
+
<span class='kw'>end</span>
|
|
109
|
+
</code></pre>
|
|
110
|
+
|
|
111
|
+
<h2 id="label-The+Show+component">The Show component</h2>
|
|
112
|
+
|
|
113
|
+
<p>This components loads a user by reading the param <code>id</code>. It then displays a simple table showing all the fields defined above.</p>
|
|
114
|
+
|
|
115
|
+
<p>We will implement this component on our own, giving you an insight into many of Compony’s mechanisms:</p>
|
|
116
|
+
|
|
117
|
+
<pre class="code ruby"><code class="ruby"><span class='comment'># All components (except abstract ones) must be placed in the `Components` namespace living under `app/components`.
|
|
118
|
+
</span><span class='comment'># They must be nested in another namespace, called "family" (here, `Users`), followed by the component's name (here, `Show`).
|
|
119
|
+
</span><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'><</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>
|
|
120
|
+
<span class='comment'># The Resourceful mixin causes a component to automatically load a model from the `id` parameter and store it under `@data`.
|
|
121
|
+
</span> <span class='comment'># The model's class is inferred from the component's name: `Users::Show` -> `User`
|
|
122
|
+
</span> <span class='id identifier rubyid_include'>include</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/ComponentMixins.html" title="Compony::ComponentMixins (module)">ComponentMixins</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Compony/ComponentMixins/Resourceful.html" title="Compony::ComponentMixins::Resourceful (module)">Resourceful</a></span></span>
|
|
123
|
+
|
|
124
|
+
<span class='comment'># Components are configured in the `setup` method, which prevents loading order issues.
|
|
125
|
+
</span> <span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
|
|
126
|
+
<span class='comment'># The DSL call `label` defines what is the title of the component and which text is displayed on links as well as buttons pointing to it.
|
|
127
|
+
</span> <span class='comment'># It accepts different formats and takes a block. Given that this component always loads one model, the block must take an argument which is the model.
|
|
128
|
+
</span> <span class='comment'># The argument must be provided by links and buttons pointing to this component.
|
|
129
|
+
</span> <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__u'>_u</span><span class='op'>|</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Show</span><span class='tstring_end'>'</span></span> <span class='rbrace'>}</span> <span class='comment'># The short format is suitable for e.g. a button in a list of users.
|
|
130
|
+
</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_u'>u</span><span class='op'>|</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='tstring_content'>Show user </span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_u'>u</span><span class='period'>.</span><span class='id identifier rubyid_label'>label</span><span class='embexpr_end'>}</span><span class='tstring_end'>"</span></span> <span class='rbrace'>}</span> <span class='comment'># The long format is suitable e.g. in a link in a text about this user.
|
|
131
|
+
</span>
|
|
132
|
+
<span class='comment'># Intents point to other components. They have a name that is used to identify them and encapsulate both the target component and current context.
|
|
133
|
+
</span> <span class='comment'># Exposed intents can be rendered by the application layout.
|
|
134
|
+
</span> <span class='id identifier rubyid_exposed_intents'>exposed_intents</span> <span class='kw'>do</span>
|
|
135
|
+
<span class='id identifier rubyid_add'>add</span> <span class='symbol'>:index</span><span class='comma'>,</span> <span class='symbol'>:users</span> <span class='comment'># This points to `Components::Users::Index` without passing a model (because it's an index).
|
|
136
|
+
</span> <span class='id identifier rubyid_add'>add</span> <span class='symbol'>:edit</span><span class='comma'>,</span> <span class='ivar'>@data</span> <span class='comment'># This points to `Components::Users::Edit` for the currently loaded model. This also checks feasibility.
|
|
137
|
+
</span> <span class='kw'>end</span>
|
|
138
|
+
|
|
139
|
+
<span class='comment'># When a standalone config is present, Compony creates one or multiple Rails routes. Components without standalone config must be nested within others.
|
|
140
|
+
</span> <span class='id identifier rubyid_standalone'>standalone</span> <span class='label'>path:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>users/show/:id</span><span class='tstring_end'>'</span></span> <span class='kw'>do</span> <span class='comment'># This specifies the path to this component.
|
|
141
|
+
</span> <span class='id identifier rubyid_verb'>verb</span> <span class='symbol'>:get</span> <span class='kw'>do</span> <span class='comment'># This speficies that a GET route should be created for the path specified above.
|
|
142
|
+
</span> <span class='id identifier rubyid_authorize'>authorize</span> <span class='lbrace'>{</span> <span class='kw'>true</span> <span class='rbrace'>}</span> <span class='comment'># Immediately after loading the model, this is called to check for authorization. `true` means that anybody can get access.
|
|
143
|
+
</span> <span class='kw'>end</span>
|
|
144
|
+
<span class='kw'>end</span>
|
|
145
|
+
|
|
146
|
+
<span class='comment'># After loading the model and passing authorization, the `content` block is evaluated. This is Compony's equivalent to Rails' views.
|
|
147
|
+
</span> <span class='comment'># Inside the `content` block, the templating Gem Dyny (https://github.com/kalsan/dyny) is used, allowing you to write views in plain Ruby.
|
|
148
|
+
</span> <span class='id identifier rubyid_content'>content</span> <span class='kw'>do</span>
|
|
149
|
+
<span class='id identifier rubyid_h3'>h3</span> <span class='ivar'>@data</span><span class='period'>.</span><span class='id identifier rubyid_label'>label</span> <span class='comment'># Display a <h3> title
|
|
150
|
+
</span> <span class='id identifier rubyid_table'>table</span> <span class='kw'>do</span> <span class='comment'># Open a <table> tag
|
|
151
|
+
</span> <span class='id identifier rubyid_tr'>tr</span> <span class='kw'>do</span> <span class='comment'># Open a <tr> tag
|
|
152
|
+
</span> <span class='comment'># Iterate over all the fields defined in the model above and display its translated label (this uses Rails' `human_attribute_name`), e.g. "Name".
|
|
153
|
+
</span> <span class='ivar'>@data</span><span class='period'>.</span><span class='id identifier rubyid_fields'>fields</span><span class='period'>.</span><span class='id identifier rubyid_each_value'>each_value</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_field'>field</span><span class='op'>|</span> <span class='id identifier rubyid_th'>th</span> <span class='id identifier rubyid_field'>field</span><span class='period'>.</span><span class='id identifier rubyid_label'>label</span> <span class='rbrace'>}</span>
|
|
154
|
+
<span class='kw'>end</span> <span class='comment'># Closing </tr>
|
|
155
|
+
</span> <span class='id identifier rubyid_tr'>tr</span> <span class='kw'>do</span>
|
|
156
|
+
<span class='comment'># Iterate over the fields again and call `value_for` which formats each field's value according to the field type.
|
|
157
|
+
</span> <span class='ivar'>@data</span><span class='period'>.</span><span class='id identifier rubyid_fields'>fields</span><span class='period'>.</span><span class='id identifier rubyid_each_value'>each_value</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_field'>field</span><span class='op'>|</span> <span class='id identifier rubyid_td'>td</span> <span class='id identifier rubyid_field'>field</span><span class='period'>.</span><span class='id identifier rubyid_value_for'>value_for</span><span class='lparen'>(</span><span class='ivar'>@data</span><span class='rparen'>)</span> <span class='rbrace'>}</span>
|
|
158
|
+
<span class='kw'>end</span>
|
|
159
|
+
<span class='kw'>end</span>
|
|
160
|
+
<span class='kw'>end</span>
|
|
161
|
+
<span class='kw'>end</span>
|
|
162
|
+
<span class='kw'>end</span>
|
|
163
|
+
</code></pre>
|
|
164
|
+
|
|
165
|
+
<p>Here is what our Show component looks like when we have a layout with the bare minimum and no styling at all:</p>
|
|
166
|
+
|
|
167
|
+
<p><img src="/doc/imgs/intro-example-show.png"></p>
|
|
168
|
+
|
|
169
|
+
<p>It is important to note that button styles, navigation, notifications etc. are handled by the application layout. In this and the subsequent screenshots, we explicitely use minimalism, as it makes the generated HTML clearer.</p>
|
|
170
|
+
|
|
171
|
+
<h2 id="label-The+Destroy+component">The Destroy component</h2>
|
|
172
|
+
|
|
173
|
+
<p>Compony has a built-in abstract <code>Destroy</code> component which displays a confirmation message and destroys the record if the verb is <code>DELETE</code>. This is a good example for how DRY code can become for “boring” components. Since everything is provided with an overridable default, components without special logic can actually be left blank:</p>
|
|
174
|
+
|
|
175
|
+
<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'>Destroy</span> <span class='op'><</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/Components.html" title="Compony::Components (module)">Components</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Compony/Components/Destroy.html" title="Compony::Components::Destroy (class)">Destroy</a></span></span>
|
|
176
|
+
<span class='kw'>end</span>
|
|
177
|
+
</code></pre>
|
|
178
|
+
|
|
179
|
+
<p>Note that this component is fully functional. All is handled by the class it inherits from:</p>
|
|
180
|
+
|
|
181
|
+
<p><img src="/doc/imgs/intro-example-destroy.png"></p>
|
|
182
|
+
|
|
183
|
+
<h2 id="label-The+New+component+and+the+Form+component">The New component and the Form component</h2>
|
|
184
|
+
|
|
185
|
+
<p>Compony also has a pre-built abstract <code>New</code> component that handles routing and resource manipulation. It combines the controller actions <code>new</code> and <code>create</code>, depending on the HTTP verb of the request. Since it’s pre-built, any “boring” code can be omitted and our <code>New</code> components looks like this:</p>
|
|
186
|
+
|
|
187
|
+
<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'>New</span> <span class='op'><</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/Components.html" title="Compony::Components (module)">Components</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Compony/Components/New.html" title="Compony::Components::New (class)">New</a></span></span>
|
|
188
|
+
<span class='kw'>end</span>
|
|
189
|
+
</code></pre>
|
|
190
|
+
|
|
191
|
+
<p>By default, this component looks for another component called <code>Form</code> in the same directory, which can look like this:</p>
|
|
192
|
+
|
|
193
|
+
<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'>Form</span> <span class='op'><</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/Components.html" title="Compony::Components (module)">Components</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Compony/Components/Form.html" title="Compony::Components::Form (class)">Form</a></span></span>
|
|
194
|
+
<span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
|
|
195
|
+
<span class='comment'># This mandatory DSL call prepares and opens a form in which you can write your HTML in Dyny.
|
|
196
|
+
</span> <span class='comment'># The form is realized using the simple_form Gem (https://github.com/heartcombo/simple_form).
|
|
197
|
+
</span> <span class='comment'># Inside this block, more DSL calls are available, such as `field`, which automatically generates
|
|
198
|
+
</span> <span class='comment'># a suitable simple_form input from the field specified in the model.
|
|
199
|
+
</span> <span class='id identifier rubyid_form_fields'>form_fields</span> <span class='kw'>do</span>
|
|
200
|
+
<span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_field'>field</span><span class='lparen'>(</span><span class='symbol'>:name</span><span class='rparen'>)</span> <span class='comment'># `field` checks the model to find out that a string input is needed here. `concat` is the Dyny equivalent to ERB's <%= %>.
|
|
201
|
+
</span> <span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_field'>field</span><span class='lparen'>(</span><span class='symbol'>:age</span><span class='rparen'>)</span>
|
|
202
|
+
<span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_field'>field</span><span class='lparen'>(</span><span class='symbol'>:comment</span><span class='rparen'>)</span>
|
|
203
|
+
<span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_field'>field</span><span class='lparen'>(</span><span class='symbol'>:role</span><span class='rparen'>)</span> <span class='comment'># Compony has built-in support for Anchormodel and as the model declares `role` to be of type `anchormodel`, a select is rendered.
|
|
204
|
+
</span> <span class='kw'>end</span>
|
|
205
|
+
|
|
206
|
+
<span class='comment'># This DSL call is mandatory as well and automatically generates strong param validation for this form.
|
|
207
|
+
</span> <span class='comment'># The generated underlying implementation is Schemacop V3 (https://github.com/sitrox/schemacop/blob/master/README_V3.md).
|
|
208
|
+
</span> <span class='id identifier rubyid_schema_fields'>schema_fields</span> <span class='symbol'>:name</span><span class='comma'>,</span> <span class='symbol'>:age</span><span class='comma'>,</span> <span class='symbol'>:comment</span><span class='comma'>,</span> <span class='symbol'>:role</span>
|
|
209
|
+
<span class='kw'>end</span>
|
|
210
|
+
<span class='kw'>end</span>
|
|
211
|
+
</code></pre>
|
|
212
|
+
|
|
213
|
+
<p>This is enough to render a fully functional form that creates new users:</p>
|
|
214
|
+
|
|
215
|
+
<p><img src="/doc/imgs/intro-example-new.png"></p>
|
|
216
|
+
|
|
217
|
+
<h2 id="label-The+Edit+component">The Edit component</h2>
|
|
218
|
+
|
|
219
|
+
<p>Just like <code>New</code>, <code>Edit</code> is a pre-built component that handles routing and resource manipulation for editing models, combinding the controller actions <code>edit</code> and <code>update</code> depending on the HTTP verb. It uses that same <code>Form</code> component we wrote above and thus the code is as simple as:</p>
|
|
220
|
+
|
|
221
|
+
<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'>Edit</span> <span class='op'><</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/Components.html" title="Compony::Components (module)">Components</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Compony/Components/Edit.html" title="Compony::Components::Edit (class)">Edit</a></span></span>
|
|
222
|
+
<span class='kw'>end</span>
|
|
223
|
+
</code></pre>
|
|
224
|
+
|
|
225
|
+
<p>It then looks like this:</p>
|
|
226
|
+
|
|
227
|
+
<p><img src="/doc/imgs/intro-example-edit.png"></p>
|
|
228
|
+
|
|
229
|
+
<h2 id="label-The+Index+component">The Index component</h2>
|
|
230
|
+
|
|
231
|
+
<p>This component should list all users and provide buttons to manage them. We’ll build it from scratch and make it resourceful, where <code>@data</code> holds the ActiveRecord relation.</p>
|
|
232
|
+
|
|
233
|
+
<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'>Index</span> <span class='op'><</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>
|
|
234
|
+
<span class='comment'># Making the component resourceful enables a few features for dealing with @data.
|
|
235
|
+
</span> <span class='id identifier rubyid_include'>include</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/ComponentMixins.html" title="Compony::ComponentMixins (module)">ComponentMixins</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="Compony/ComponentMixins/Resourceful.html" title="Compony::ComponentMixins::Resourceful (module)">Resourceful</a></span></span>
|
|
236
|
+
|
|
237
|
+
<span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
|
|
238
|
+
<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'>'</span><span class='tstring_content'>Users</span><span class='tstring_end'>'</span></span> <span class='rbrace'>}</span> <span class='comment'># This sets all labels (long and short) to 'Users'. When pointing to this component using buttons, we will not provide a model.
|
|
239
|
+
</span> <span class='id identifier rubyid_standalone'>standalone</span> <span class='label'>path:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>users</span><span class='tstring_end'>'</span></span> <span class='kw'>do</span> <span class='comment'># The path is simply /users, without a param. This conflicts with `Resourceful`, which we will fix in `load_data`.
|
|
240
|
+
</span> <span class='id identifier rubyid_verb'>verb</span> <span class='symbol'>:get</span> <span class='kw'>do</span>
|
|
241
|
+
<span class='id identifier rubyid_authorize'>authorize</span> <span class='lbrace'>{</span> <span class='kw'>true</span> <span class='rbrace'>}</span>
|
|
242
|
+
<span class='kw'>end</span>
|
|
243
|
+
<span class='kw'>end</span>
|
|
244
|
+
|
|
245
|
+
<span class='comment'># This DSL call is specific to resourceful components and overrides how a model is loaded.
|
|
246
|
+
</span> <span class='comment'># The block is called before authorization and must assign a model or collection to `@data`.
|
|
247
|
+
</span> <span class='id identifier rubyid_load_data'>load_data</span> <span class='lbrace'>{</span> <span class='ivar'>@data</span> <span class='op'>=</span> <span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_all'>all</span> <span class='rbrace'>}</span>
|
|
248
|
+
|
|
249
|
+
<span class='id identifier rubyid_content'>content</span> <span class='kw'>do</span>
|
|
250
|
+
<span class='id identifier rubyid_h4'>h4</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Users:</span><span class='tstring_end'>'</span></span> <span class='comment'># Provide a title
|
|
251
|
+
</span> <span class='comment'># Provide a button that creates a new user. Note that we must write `:users` (plural) because the component's family is `Users`.
|
|
252
|
+
</span> <span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_render_intent'>render_intent</span><span class='lparen'>(</span><span class='symbol'>:new</span><span class='comma'>,</span> <span class='symbol'>:users</span><span class='rparen'>)</span> <span class='comment'># The `Users::New` component does not take a model, thus we just pass the symbol `:users`, not a model.
|
|
253
|
+
</span>
|
|
254
|
+
<span class='id identifier rubyid_div'>div</span> <span class='label'>class:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>users</span><span class='tstring_end'>'</span></span> <span class='kw'>do</span> <span class='comment'># Opening tag <div class="users">
|
|
255
|
+
</span> <span class='ivar'>@data</span><span class='period'>.</span><span class='id identifier rubyid_each'>each</span> <span class='kw'>do</span> <span class='op'>|</span><span class='id identifier rubyid_user'>user</span><span class='op'>|</span> <span class='comment'># Iterate the collection
|
|
256
|
+
</span> <span class='id identifier rubyid_div'>div</span> <span class='label'>class:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>user</span><span class='tstring_end'>'</span></span> <span class='kw'>do</span> <span class='comment'># For each element, open another div
|
|
257
|
+
</span> <span class='const'>User</span><span class='period'>.</span><span class='id identifier rubyid_fields'>fields</span><span class='period'>.</span><span class='id identifier rubyid_values'>values</span><span class='period'>.</span><span class='id identifier rubyid_each'>each</span> <span class='kw'>do</span> <span class='op'>|</span><span class='id identifier rubyid_field'>field</span><span class='op'>|</span> <span class='comment'># For each user, iterate all fields
|
|
258
|
+
</span> <span class='id identifier rubyid_span'>span</span> <span class='kw'>do</span> <span class='comment'># Open a <span> tag
|
|
259
|
+
</span> <span class='id identifier rubyid_concat'>concat</span> <span class='tstring'><span class='tstring_beg'>"</span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_field'>field</span><span class='period'>.</span><span class='id identifier rubyid_label'>label</span><span class='embexpr_end'>}</span><span class='tstring_content'>: </span><span class='embexpr_beg'>#{</span><span class='id identifier rubyid_field'>field</span><span class='period'>.</span><span class='id identifier rubyid_value_for'>value_for</span><span class='lparen'>(</span><span class='id identifier rubyid_user'>user</span><span class='rparen'>)</span><span class='embexpr_end'>}</span><span class='tstring_content'> </span><span class='tstring_end'>"</span></span> <span class='comment'># Display the field's label and apply it to value, as we did in the Show component.
|
|
260
|
+
</span> <span class='kw'>end</span>
|
|
261
|
+
<span class='kw'>end</span>
|
|
262
|
+
<span class='comment'># For each user, add three buttons show, edit, destroy.
|
|
263
|
+
</span> <span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_render_intent'>render_intent</span><span class='lparen'>(</span><span class='symbol'>:show</span><span class='comma'>,</span> <span class='id identifier rubyid_user'>user</span><span class='comma'>,</span> <span class='label'>button:</span> <span class='lbrace'>{</span> <span class='label'>label:</span> <span class='lbrace'>{</span> <span class='label'>format:</span> <span class='symbol'>:short</span> <span class='rbrace'>}</span><span class='rbrace'>}</span><span class='rparen'>)</span>
|
|
264
|
+
<span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_render_intent'>render_intent</span><span class='lparen'>(</span><span class='symbol'>:edit</span><span class='comma'>,</span> <span class='id identifier rubyid_user'>user</span><span class='comma'>,</span> <span class='label'>button:</span> <span class='lbrace'>{</span> <span class='label'>label:</span> <span class='lbrace'>{</span> <span class='label'>format:</span> <span class='symbol'>:short</span> <span class='rbrace'>}</span><span class='rbrace'>}</span><span class='rparen'>)</span>
|
|
265
|
+
<span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_render_intent'>render_intent</span><span class='lparen'>(</span><span class='symbol'>:destroy</span><span class='comma'>,</span> <span class='id identifier rubyid_user'>user</span><span class='comma'>,</span> <span class='label'>button:</span> <span class='lbrace'>{</span> <span class='label'>label:</span> <span class='lbrace'>{</span> <span class='label'>format:</span> <span class='symbol'>:short</span> <span class='rbrace'>}</span><span class='rbrace'>}</span><span class='rparen'>)</span>
|
|
266
|
+
<span class='kw'>end</span>
|
|
267
|
+
<span class='kw'>end</span>
|
|
268
|
+
<span class='kw'>end</span>
|
|
269
|
+
<span class='kw'>end</span>
|
|
270
|
+
<span class='kw'>end</span>
|
|
271
|
+
<span class='kw'>end</span>
|
|
272
|
+
</code></pre>
|
|
273
|
+
|
|
274
|
+
<p>The result looks like this:</p>
|
|
275
|
+
|
|
276
|
+
<p><img src="/doc/imgs/intro-example-index.png"></p>
|
|
277
|
+
|
|
278
|
+
<p>Note how the admin’s delete button is disabled due to the feasibility framework. Pointing the mouse at it causes a tooltip saying: “Cannot destroy admins.”, as specified in the model’s prevention.</p>
|
|
279
|
+
|
|
280
|
+
<p><a href="/README_md.html#guide--documentation">Guide index</a></p>
|
|
281
|
+
</div></div>
|
|
282
|
+
|
|
283
|
+
<div id="footer">
|
|
284
|
+
Generated on Mon May 18 13:55:32 2026 by
|
|
285
|
+
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
286
|
+
0.9.34 (ruby-3.3.5).
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
</div>
|
|
290
|
+
</body>
|
|
291
|
+
</html>
|