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
|
@@ -0,0 +1,257 @@
|
|
|
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_advanced
|
|
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_advanced";
|
|
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_advanced</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-Advanced+example">Advanced example</h1>
|
|
64
|
+
|
|
65
|
+
<p><a href="/doc/guide/example_md.html">example.md</a> shows the basics. This one combines patterns you hit in real apps: a custom form, feasibility, exposed intents, a CSV export endpoint, a <code>before_render</code> guard, and a virtual-model launch form for a background job.</p>
|
|
66
|
+
|
|
67
|
+
<p>Domain: invoicing. An <code>Invoice</code> has line items, can be locked, exported as CSV, and a background “send reminders” job can be launched from a non-persistent form.</p>
|
|
68
|
+
|
|
69
|
+
<h2 id="label-The+models">The models</h2>
|
|
70
|
+
|
|
71
|
+
<pre class="code ruby"><code class="ruby"><span class='comment'># app/models/invoice.rb
|
|
72
|
+
</span><span class='kw'>class</span> <span class='const'>Invoice</span> <span class='op'><</span> <span class='const'>ApplicationRecord</span>
|
|
73
|
+
<span class='id identifier rubyid_has_many'>has_many</span> <span class='symbol'>:line_items</span><span class='comma'>,</span> <span class='label'>dependent:</span> <span class='symbol'>:destroy</span>
|
|
74
|
+
<span class='id identifier rubyid_accepts_nested_attributes_for'>accepts_nested_attributes_for</span> <span class='symbol'>:line_items</span><span class='comma'>,</span> <span class='label'>allow_destroy:</span> <span class='kw'>true</span>
|
|
75
|
+
<span class='id identifier rubyid_belongs_to'>belongs_to</span> <span class='symbol'>:customer</span>
|
|
76
|
+
|
|
77
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:number</span><span class='comma'>,</span> <span class='symbol'>:string</span>
|
|
78
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:customer</span><span class='comma'>,</span> <span class='symbol'>:association</span>
|
|
79
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:total</span><span class='comma'>,</span> <span class='symbol'>:decimal</span>
|
|
80
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:locked</span><span class='comma'>,</span> <span class='symbol'>:boolean</span>
|
|
81
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:issued_at</span><span class='comma'>,</span> <span class='symbol'>:datetime</span>
|
|
82
|
+
|
|
83
|
+
<span class='kw'>def</span> <span class='id identifier rubyid_label'>label</span> <span class='op'>=</span> <span class='id identifier rubyid_number'>number</span>
|
|
84
|
+
|
|
85
|
+
<span class='comment'># Feasibility: a locked invoice must not be edited or destroyed.
|
|
86
|
+
</span> <span class='comment'># Back every important prevention with a real validation (see note in feasibility.md).
|
|
87
|
+
</span> <span class='id identifier rubyid_prevent'>prevent</span> <span class='qsymbols_beg'>%i[</span><span class='tstring_content'>edit</span><span class='words_sep'> </span><span class='tstring_content'>destroy</span><span class='tstring_end'>]</span></span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>the invoice is locked</span><span class='tstring_end'>'</span></span> <span class='kw'>do</span>
|
|
88
|
+
<span class='id identifier rubyid_locked?'>locked?</span>
|
|
89
|
+
<span class='kw'>end</span>
|
|
90
|
+
<span class='id identifier rubyid_validate'>validate</span> <span class='lbrace'>{</span> <span class='id identifier rubyid_errors'>errors</span><span class='period'>.</span><span class='id identifier rubyid_add'>add</span><span class='lparen'>(</span><span class='symbol'>:base</span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>invoice is locked</span><span class='tstring_end'>'</span></span><span class='rparen'>)</span> <span class='kw'>if</span> <span class='id identifier rubyid_locked_was'>locked_was</span> <span class='op'>&&</span> <span class='id identifier rubyid_locked?'>locked?</span> <span class='rbrace'>}</span>
|
|
91
|
+
<span class='kw'>end</span>
|
|
92
|
+
|
|
93
|
+
<span class='comment'># app/models/line_item.rb
|
|
94
|
+
</span><span class='kw'>class</span> <span class='const'>LineItem</span> <span class='op'><</span> <span class='const'>ApplicationRecord</span>
|
|
95
|
+
<span class='id identifier rubyid_belongs_to'>belongs_to</span> <span class='symbol'>:invoice</span>
|
|
96
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:description</span><span class='comma'>,</span> <span class='symbol'>:string</span>
|
|
97
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:amount</span><span class='comma'>,</span> <span class='symbol'>:decimal</span>
|
|
98
|
+
<span class='kw'>def</span> <span class='id identifier rubyid_label'>label</span> <span class='op'>=</span> <span class='id identifier rubyid_description'>description</span>
|
|
99
|
+
<span class='kw'>end</span>
|
|
100
|
+
</code></pre>
|
|
101
|
+
|
|
102
|
+
<h2 id="label-Index+with+a+CSV+export+endpoint+and+exposed+intents">Index with a CSV export endpoint and exposed intents</h2>
|
|
103
|
+
|
|
104
|
+
<p>One component, two routes: the HTML list and a <code>.csv</code> download. The CSV intent is exposed so the layout renders a “Download CSV” button in the page header.</p>
|
|
105
|
+
|
|
106
|
+
<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'>Invoices</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>
|
|
107
|
+
<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>
|
|
108
|
+
|
|
109
|
+
<span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
|
|
110
|
+
<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'>Invoices</span><span class='tstring_end'>'</span></span> <span class='rbrace'>}</span>
|
|
111
|
+
|
|
112
|
+
<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'>invoices</span><span class='tstring_end'>'</span></span> <span class='kw'>do</span>
|
|
113
|
+
<span class='id identifier rubyid_verb'>verb</span> <span class='symbol'>:get</span> <span class='kw'>do</span>
|
|
114
|
+
<span class='id identifier rubyid_authorize'>authorize</span> <span class='lbrace'>{</span> <span class='id identifier rubyid_can?'>can?</span><span class='lparen'>(</span><span class='symbol'>:read</span><span class='comma'>,</span> <span class='const'>Invoice</span><span class='rparen'>)</span> <span class='rbrace'>}</span>
|
|
115
|
+
<span class='comment'># Default (HTML) response renders content. CSV gets its own response:
|
|
116
|
+
</span> <span class='id identifier rubyid_respond'>respond</span> <span class='symbol'>:csv</span> <span class='kw'>do</span>
|
|
117
|
+
<span class='id identifier rubyid_authorize_csv'>authorize_csv</span> <span class='op'>=</span> <span class='id identifier rubyid_can?'>can?</span><span class='lparen'>(</span><span class='symbol'>:read</span><span class='comma'>,</span> <span class='const'>Invoice</span><span class='rparen'>)</span> <span class='kw'>or</span> <span class='id identifier rubyid_raise'>raise</span> <span class='const'>CanCan</span><span class='op'>::</span><span class='const'>AccessDenied</span> <span class='comment'># respond skips authorize!
|
|
118
|
+
</span> <span class='id identifier rubyid_send_data'>send_data</span><span class='lparen'>(</span><span class='const'>InvoiceCsv</span><span class='period'>.</span><span class='id identifier rubyid_new'>new</span><span class='lparen'>(</span><span class='ivar'>@data</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_to_csv'>to_csv</span><span class='comma'>,</span> <span class='label'>filename:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>invoices.csv</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>type:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>text/csv</span><span class='tstring_end'>'</span></span><span class='rparen'>)</span>
|
|
119
|
+
<span class='kw'>end</span>
|
|
120
|
+
<span class='kw'>end</span>
|
|
121
|
+
<span class='kw'>end</span>
|
|
122
|
+
|
|
123
|
+
<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'>Invoice</span><span class='period'>.</span><span class='id identifier rubyid_accessible_by'>accessible_by</span><span class='lparen'>(</span><span class='id identifier rubyid_current_ability'>current_ability</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_order'>order</span><span class='lparen'>(</span><span class='label'>issued_at:</span> <span class='symbol'>:desc</span><span class='rparen'>)</span> <span class='rbrace'>}</span>
|
|
124
|
+
|
|
125
|
+
<span class='id identifier rubyid_exposed_intents'>exposed_intents</span> <span class='kw'>do</span>
|
|
126
|
+
<span class='id identifier rubyid_add'>add</span> <span class='symbol'>:index</span><span class='comma'>,</span> <span class='symbol'>:invoices</span><span class='comma'>,</span> <span class='label'>label:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Download CSV</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>name:</span> <span class='symbol'>:csv</span><span class='comma'>,</span> <span class='label'>path:</span> <span class='lbrace'>{</span> <span class='label'>format:</span> <span class='symbol'>:csv</span> <span class='rbrace'>}</span>
|
|
127
|
+
<span class='id identifier rubyid_add'>add</span> <span class='symbol'>:request_reminders</span><span class='comma'>,</span> <span class='symbol'>:invoices</span><span class='comma'>,</span> <span class='label'>label:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Send reminders</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>method:</span> <span class='symbol'>:get</span>
|
|
128
|
+
<span class='kw'>end</span>
|
|
129
|
+
|
|
130
|
+
<span class='id identifier rubyid_content'>content</span> <span class='kw'>do</span>
|
|
131
|
+
<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'>:invoices</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>
|
|
132
|
+
<span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_render_sub_comp'>render_sub_comp</span><span class='lparen'>(</span><span class='symbol'>:list</span><span class='comma'>,</span> <span class='ivar'>@data</span><span class='rparen'>)</span>
|
|
133
|
+
<span class='kw'>end</span>
|
|
134
|
+
<span class='kw'>end</span>
|
|
135
|
+
<span class='kw'>end</span>
|
|
136
|
+
</code></pre>
|
|
137
|
+
|
|
138
|
+
<p>Notes:</p>
|
|
139
|
+
<ul><li>
|
|
140
|
+
<p><code>respond :csv</code> handles <code>GET /invoices.csv</code>. Because overriding <code>respond</code> <strong>skips the default <code>authorize</code></strong> (see <a href="/doc/guide/gotchas_md.html#3-overriding-respond-skips-authorization">gotchas.md</a>), the CSV branch re-checks the ability itself.</p>
|
|
141
|
+
</li><li>
|
|
142
|
+
<p><code>path: { format: :csv }</code> on the exposed intent makes its button point at <code>.csv</code>.</p>
|
|
143
|
+
</li><li>
|
|
144
|
+
<p>The layout renders exposed intents of <code>Compony.root_comp</code> — see <a href="/doc/guide/intents_md.html#rendering-exposed-intents">intents.md</a>.</p>
|
|
145
|
+
</li></ul>
|
|
146
|
+
|
|
147
|
+
<h2 id="label-A+custom+Form+with+nested+line+items">A custom Form with nested line items</h2>
|
|
148
|
+
|
|
149
|
+
<p><code>Edit</code>/<code>New</code> look for <code>Components::Invoices::Form</code> by default. We write it with <code>accepts_nested_attributes_for</code> via <code>simple_form</code>‘s <code>simple_fields_for</code>, and whitelist the nested params with a raw <code>schema_line</code>.</p>
|
|
150
|
+
|
|
151
|
+
<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'>Invoices</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>
|
|
152
|
+
<span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
|
|
153
|
+
<span class='id identifier rubyid_form_fields'>form_fields</span> <span class='kw'>do</span>
|
|
154
|
+
<span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_field'>field</span><span class='lparen'>(</span><span class='symbol'>:number</span><span class='rparen'>)</span>
|
|
155
|
+
<span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_field'>field</span><span class='lparen'>(</span><span class='symbol'>:customer</span><span class='comma'>,</span> <span class='label'>as:</span> <span class='symbol'>:tom_select</span><span class='rparen'>)</span> <span class='comment'># association name, NOT customer_id
|
|
156
|
+
</span> <span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_field'>field</span><span class='lparen'>(</span><span class='symbol'>:issued_at</span><span class='comma'>,</span> <span class='label'>as:</span> <span class='symbol'>:flatpickr_datetime</span><span class='rparen'>)</span>
|
|
157
|
+
<span class='id identifier rubyid_concat'>concat</span><span class='lparen'>(</span><span class='id identifier rubyid_f'>f</span><span class='period'>.</span><span class='id identifier rubyid_simple_fields_for'>simple_fields_for</span><span class='lparen'>(</span><span class='symbol'>:line_items</span><span class='rparen'>)</span> <span class='kw'>do</span> <span class='op'>|</span><span class='id identifier rubyid_lf'>lf</span><span class='op'>|</span>
|
|
158
|
+
<span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_lf'>lf</span><span class='period'>.</span><span class='id identifier rubyid_input'>input</span><span class='lparen'>(</span><span class='symbol'>:description</span><span class='rparen'>)</span>
|
|
159
|
+
<span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_lf'>lf</span><span class='period'>.</span><span class='id identifier rubyid_input'>input</span><span class='lparen'>(</span><span class='symbol'>:amount</span><span class='rparen'>)</span>
|
|
160
|
+
<span class='kw'>end</span><span class='rparen'>)</span>
|
|
161
|
+
<span class='kw'>end</span>
|
|
162
|
+
|
|
163
|
+
<span class='id identifier rubyid_schema_fields'>schema_fields</span> <span class='symbol'>:number</span><span class='comma'>,</span> <span class='symbol'>:customer</span><span class='comma'>,</span> <span class='symbol'>:issued_at</span>
|
|
164
|
+
<span class='comment'># Nested attributes need a manual Schemacop line:
|
|
165
|
+
</span> <span class='id identifier rubyid_schema_line'>schema_line</span> <span class='kw'>do</span>
|
|
166
|
+
<span class='id identifier rubyid_ary?'>ary?</span> <span class='symbol'>:line_items_attributes</span> <span class='kw'>do</span>
|
|
167
|
+
<span class='id identifier rubyid_list'>list</span> <span class='symbol'>:hash</span> <span class='kw'>do</span>
|
|
168
|
+
<span class='id identifier rubyid_int?'>int?</span> <span class='symbol'>:id</span>
|
|
169
|
+
<span class='id identifier rubyid_str?'>str?</span> <span class='symbol'>:description</span>
|
|
170
|
+
<span class='id identifier rubyid_num?'>num?</span> <span class='symbol'>:amount</span>
|
|
171
|
+
<span class='id identifier rubyid_boo?'>boo?</span> <span class='symbol'>:_destroy</span>
|
|
172
|
+
<span class='kw'>end</span>
|
|
173
|
+
<span class='kw'>end</span>
|
|
174
|
+
<span class='kw'>end</span>
|
|
175
|
+
<span class='kw'>end</span>
|
|
176
|
+
<span class='kw'>end</span>
|
|
177
|
+
</code></pre>
|
|
178
|
+
|
|
179
|
+
<p><code>schema_field :customer</code> (association name) lets Compony add <code>customer_id</code> automatically — passing <code>:customer_id</code> here would not work (<a href="/doc/guide/gotchas_md.html#4-schema_field-with-the-foreign-key-name">gotchas.md</a>).</p>
|
|
180
|
+
|
|
181
|
+
<h2 id="label-Edit-3A+thin-2C+plus+a+guard+and+a+custom+redirect">Edit: thin, plus a guard and a custom redirect</h2>
|
|
182
|
+
|
|
183
|
+
<p><code>Edit</code> inherits all CRUD wiring. We only add a <code>before_render</code> guard (independent of HTTP verb) and override where a successful save lands.</p>
|
|
184
|
+
|
|
185
|
+
<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'>Invoices</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>
|
|
186
|
+
<span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
|
|
187
|
+
<span class='id identifier rubyid_before_render'>before_render</span> <span class='kw'>do</span>
|
|
188
|
+
<span class='kw'>if</span> <span class='ivar'>@data</span><span class='period'>.</span><span class='id identifier rubyid_locked?'>locked?</span>
|
|
189
|
+
<span class='id identifier rubyid_flash'>flash</span><span class='period'>.</span><span class='id identifier rubyid_alert'>alert</span> <span class='op'>=</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>This invoice is locked.</span><span class='tstring_end'>'</span></span>
|
|
190
|
+
<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'>:show</span><span class='comma'>,</span> <span class='ivar'>@data</span><span class='rparen'>)</span>
|
|
191
|
+
<span class='kw'>end</span>
|
|
192
|
+
<span class='kw'>end</span>
|
|
193
|
+
|
|
194
|
+
<span class='id identifier rubyid_on_updated_redirect_path'>on_updated_redirect_path</span> <span class='lbrace'>{</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'>:show</span><span class='comma'>,</span> <span class='ivar'>@data</span><span class='rparen'>)</span> <span class='rbrace'>}</span>
|
|
195
|
+
<span class='kw'>end</span>
|
|
196
|
+
<span class='kw'>end</span>
|
|
197
|
+
</code></pre>
|
|
198
|
+
|
|
199
|
+
<p>The <code>prevent :edit</code> in the model already greys out the edit button with a tooltip; the <code>before_render</code> guard plus the model validation stop a hand-crafted request (<a href="/doc/guide/feasibility_md.html">feasibility.md</a> explains why all three layers are needed).</p>
|
|
200
|
+
|
|
201
|
+
<p><code>Components::Invoices::New</code>, <code>Show</code>, <code>Destroy</code> can stay empty — the pre-built parents do the work.</p>
|
|
202
|
+
|
|
203
|
+
<h2 id="label-A+virtual-model+launch+form+for+a+background+job">A virtual-model launch form for a background job</h2>
|
|
204
|
+
|
|
205
|
+
<p>“Send reminders” should pop a small form (which customers? how many days overdue?) and, on submit, queue a job — nothing is persisted. Inherit <code>New</code>, back it with a <code>Compony::VirtualModel</code>, and take over <code>on_created_respond</code>.</p>
|
|
206
|
+
|
|
207
|
+
<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'>Invoices</span><span class='op'>::</span><span class='const'>RequestReminders</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>
|
|
208
|
+
<span class='kw'>class</span> <span class='const'>VirtualModel</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/VirtualModel.html" title="Compony::VirtualModel (class)">VirtualModel</a></span></span>
|
|
209
|
+
<span class='id identifier rubyid_attribute'>attribute</span> <span class='symbol'>:min_days_overdue</span><span class='comma'>,</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='int'>7</span>
|
|
210
|
+
<span class='id identifier rubyid_attribute'>attribute</span> <span class='symbol'>:only_locked</span><span class='comma'>,</span> <span class='symbol'>:boolean</span><span class='comma'>,</span> <span class='label'>default:</span> <span class='kw'>false</span>
|
|
211
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:min_days_overdue</span><span class='comma'>,</span> <span class='symbol'>:integer</span>
|
|
212
|
+
<span class='id identifier rubyid_field'>field</span> <span class='symbol'>:only_locked</span><span class='comma'>,</span> <span class='symbol'>:boolean</span>
|
|
213
|
+
<span class='id identifier rubyid_validates'>validates</span> <span class='symbol'>:min_days_overdue</span><span class='comma'>,</span> <span class='label'>numericality:</span> <span class='lbrace'>{</span> <span class='label'>greater_than:</span> <span class='int'>0</span> <span class='rbrace'>}</span>
|
|
214
|
+
<span class='kw'>def</span> <span class='id identifier rubyid_label'>label</span> <span class='op'>=</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>Reminder request</span><span class='tstring_end'>'</span></span>
|
|
215
|
+
<span class='kw'>end</span>
|
|
216
|
+
|
|
217
|
+
<span class='kw'>class</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>
|
|
218
|
+
<span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
|
|
219
|
+
<span class='id identifier rubyid_form_fields'>form_fields</span> <span class='kw'>do</span>
|
|
220
|
+
<span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_field'>field</span><span class='lparen'>(</span><span class='symbol'>:min_days_overdue</span><span class='rparen'>)</span>
|
|
221
|
+
<span class='id identifier rubyid_concat'>concat</span> <span class='id identifier rubyid_field'>field</span><span class='lparen'>(</span><span class='symbol'>:only_locked</span><span class='rparen'>)</span>
|
|
222
|
+
<span class='kw'>end</span>
|
|
223
|
+
<span class='id identifier rubyid_schema_fields'>schema_fields</span> <span class='symbol'>:min_days_overdue</span><span class='comma'>,</span> <span class='symbol'>:only_locked</span>
|
|
224
|
+
<span class='kw'>end</span>
|
|
225
|
+
<span class='kw'>end</span>
|
|
226
|
+
|
|
227
|
+
<span class='id identifier rubyid_setup'>setup</span> <span class='kw'>do</span>
|
|
228
|
+
<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'>invoices/request_reminders</span><span class='tstring_end'>'</span></span> <span class='comment'># avoid clashing with the New route
|
|
229
|
+
</span> <span class='id identifier rubyid_data_class'>data_class</span> <span class='const'>VirtualModel</span>
|
|
230
|
+
<span class='id identifier rubyid_form_comp_class'>form_comp_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'>Invoices</span><span class='op'>::</span><span class='const'>RequestReminders</span><span class='op'>::</span><span class='const'>Form</span>
|
|
231
|
+
<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'>Send reminders</span><span class='tstring_end'>'</span></span> <span class='rbrace'>}</span>
|
|
232
|
+
|
|
233
|
+
<span class='comment'># @data.save is a no-op (virtual). on_created_respond fires only after validations pass.
|
|
234
|
+
</span> <span class='id identifier rubyid_on_created_respond'>on_created_respond</span> <span class='kw'>do</span>
|
|
235
|
+
<span class='const'>SendRemindersJob</span><span class='period'>.</span><span class='id identifier rubyid_perform_later'>perform_later</span><span class='lparen'>(</span><span class='label'>min_days_overdue:</span> <span class='ivar'>@data</span><span class='period'>.</span><span class='id identifier rubyid_min_days_overdue'>min_days_overdue</span><span class='comma'>,</span>
|
|
236
|
+
<span class='label'>only_locked:</span> <span class='ivar'>@data</span><span class='period'>.</span><span class='id identifier rubyid_only_locked'>only_locked</span><span class='rparen'>)</span>
|
|
237
|
+
<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'>'</span><span class='tstring_content'>Reminders queued — give it a few minutes.</span><span class='tstring_end'>'</span></span>
|
|
238
|
+
<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'>:invoices</span><span class='rparen'>)</span>
|
|
239
|
+
<span class='kw'>end</span>
|
|
240
|
+
<span class='kw'>end</span>
|
|
241
|
+
<span class='kw'>end</span>
|
|
242
|
+
</code></pre>
|
|
243
|
+
|
|
244
|
+
<p>Why it works: inheriting <code>New</code> gives the <code>new</code>/<code>create</code> flow. On submit Compony validates, re-renders the form with errors on failure, otherwise calls <code>@data.save</code> (a no-op on a virtual model) and runs <code>on_created_respond</code>, where you regain control. For ActiveStorage on a virtual model, also override <code>store_data</code> to only <code>validate</code> — see <a href="/doc/guide/virtual_models_md.html">virtual_models.md</a>.</p>
|
|
245
|
+
|
|
246
|
+
<p><a href="/README_md.html#guide--documentation">Guide index</a></p>
|
|
247
|
+
</div></div>
|
|
248
|
+
|
|
249
|
+
<div id="footer">
|
|
250
|
+
Generated on Mon May 18 13:55:33 2026 by
|
|
251
|
+
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
252
|
+
0.9.34 (ruby-3.3.5).
|
|
253
|
+
</div>
|
|
254
|
+
|
|
255
|
+
</div>
|
|
256
|
+
</body>
|
|
257
|
+
</html>
|
|
@@ -0,0 +1,115 @@
|
|
|
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: feasibility
|
|
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 = "feasibility";
|
|
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: feasibility</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-Feasibility">Feasibility</h1>
|
|
64
|
+
|
|
65
|
+
<p>When a user has the permission to perform an action in general, but it is currently not feasible (for instance if the concerned object is incomplete, or if right now is not the right time to do the action), buttons pointing to that action should be disabled and a HTML <code>title</code> attribute should cause a tooltip explaining why this action cannot be performed right now.</p>
|
|
66
|
+
|
|
67
|
+
<p>This can be easily achieved with the feasibility framework, which allows you to prevent actions on conditions, along with an error message. Formulate the error message similar to Rails validation errors (first letter not capital, no period at the end), as the prevention framework is able to concatenate multiple error messages if multiple conditions prevent an action.</p>
|
|
68
|
+
|
|
69
|
+
<p>The feasibility framework currently only makes sense for resourceful components.</p>
|
|
70
|
+
|
|
71
|
+
<p>Example:</p>
|
|
72
|
+
|
|
73
|
+
<pre class="code ruby"><code class="ruby"><span class='comment'># app/models/user.rb
|
|
74
|
+
</span><span class='comment'># Prevent sending an e-mail to a user that has no e-mail address present
|
|
75
|
+
</span><span class='id identifier rubyid_prevent'>prevent</span> <span class='symbol'>:send_mail</span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>the e-mail address is missing</span><span class='tstring_end'>'</span></span> <span class='kw'>do</span>
|
|
76
|
+
<span class='id identifier rubyid_email'>email</span><span class='period'>.</span><span class='id identifier rubyid_blank?'>blank?</span>
|
|
77
|
+
<span class='kw'>end</span>
|
|
78
|
+
|
|
79
|
+
<span class='comment'># app/models/event.rb
|
|
80
|
+
</span><span class='comment'># Multiple actions can be prevented at once:
|
|
81
|
+
</span><span class='comment'># Prevent creating or removing a booking to an event that lies in the past or that is locked
|
|
82
|
+
</span><span class='id identifier rubyid_prevent'>prevent</span> <span class='lbracket'>[</span><span class='symbol'>:create_booking</span><span class='comma'>,</span> <span class='symbol'>:destroy_booking</span><span class='rbracket'>]</span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>the event is already over</span><span class='tstring_end'>'</span></span> <span class='kw'>do</span>
|
|
83
|
+
<span class='id identifier rubyid_ends_at'>ends_at</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> <span class='op'>||</span> <span class='id identifier rubyid_locked?'>locked?</span>
|
|
84
|
+
<span class='kw'>end</span>
|
|
85
|
+
</code></pre>
|
|
86
|
+
|
|
87
|
+
<p><strong>Note that the feasibility framework currently only affects buttons/links pointing to actions, not the action itself.</strong> If a user were to issue the HTTP call manually, the component happily responds and performs the action. This is why you should always back important preventions with an appropriate Rails model validation:</p>
|
|
88
|
+
<ul><li>
|
|
89
|
+
<p>The Rails model validation prevents that invalid data can be saved to the database.</p>
|
|
90
|
+
</li><li>
|
|
91
|
+
<p>The feasibility framework disables buttons and links and explains to guide the user.</p>
|
|
92
|
+
</li><li>
|
|
93
|
+
<p>Links are disabled by changing the href to <code>'#'</code> and adding the <code>.disabled</code> class, which is useful when bootstrap is used.</p>
|
|
94
|
+
</li><li>
|
|
95
|
+
<p>Authorization is orthogonal to this, limiting the actions of a specific user.</p>
|
|
96
|
+
</li><li>
|
|
97
|
+
<p>If an action is both prevented and not authorized, the authorization “wins” and the action button is not shown at all.</p>
|
|
98
|
+
</li></ul>
|
|
99
|
+
|
|
100
|
+
<p>Compony has a feature that auto-detects feasibility of some actions. In particular, it checks for <code>dependent</code> relations in the <code>has_one</code>/<code>has_many</code> relations and disables delete buttons that point to objects that have dependent objects that cannot automatically be destroyed.</p>
|
|
101
|
+
|
|
102
|
+
<p>To disable auto detection, call <code>skip_autodetect_feasibilities</code> in your model.</p>
|
|
103
|
+
|
|
104
|
+
<p><a href="/README_md.html#guide--documentation">Guide index</a></p>
|
|
105
|
+
</div></div>
|
|
106
|
+
|
|
107
|
+
<div id="footer">
|
|
108
|
+
Generated on Mon May 18 13:55:33 2026 by
|
|
109
|
+
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
110
|
+
0.9.34 (ruby-3.3.5).
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
</div>
|
|
114
|
+
</body>
|
|
115
|
+
</html>
|