compony 0.11.8 → 0.11.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +36 -1
  3. data/CHANGELOG.md +31 -0
  4. data/CLAUDE.md +85 -0
  5. data/Gemfile.lock +1 -1
  6. data/README.md +13 -3
  7. data/VERSION +1 -1
  8. data/compony.gemspec +3 -3
  9. data/doc/ComponentGenerator.html +1 -1
  10. data/doc/Components.html +1 -1
  11. data/doc/ComponentsGenerator.html +1 -1
  12. data/doc/Compony/Component.html +54 -54
  13. data/doc/Compony/ComponentMixins/Default/Labelling.html +1 -1
  14. data/doc/Compony/ComponentMixins/Default/Standalone/ResourcefulVerbDsl.html +1 -1
  15. data/doc/Compony/ComponentMixins/Default/Standalone/StandaloneDsl.html +109 -70
  16. data/doc/Compony/ComponentMixins/Default/Standalone/VerbDsl.html +64 -28
  17. data/doc/Compony/ComponentMixins/Default/Standalone.html +1 -1
  18. data/doc/Compony/ComponentMixins/Default.html +1 -1
  19. data/doc/Compony/ComponentMixins/Resourceful.html +213 -74
  20. data/doc/Compony/ComponentMixins.html +1 -1
  21. data/doc/Compony/Components/Buttons/CssButton.html +1 -1
  22. data/doc/Compony/Components/Buttons/Link.html +1 -1
  23. data/doc/Compony/Components/Buttons.html +1 -1
  24. data/doc/Compony/Components/Destroy.html +83 -29
  25. data/doc/Compony/Components/Edit.html +110 -38
  26. data/doc/Compony/Components/Form.html +551 -208
  27. data/doc/Compony/Components/Index.html +1 -1
  28. data/doc/Compony/Components/List.html +3 -3
  29. data/doc/Compony/Components/New.html +110 -38
  30. data/doc/Compony/Components/Show.html +1 -1
  31. data/doc/Compony/Components/WithForm.html +194 -47
  32. data/doc/Compony/Components.html +1 -1
  33. data/doc/Compony/ControllerMixin.html +1 -1
  34. data/doc/Compony/Engine.html +1 -1
  35. data/doc/Compony/Intent.html +2 -2
  36. data/doc/Compony/ManageIntentsDsl.html +1 -1
  37. data/doc/Compony/MethodAccessibleHash.html +1 -1
  38. data/doc/Compony/ModelFields/Anchormodel.html +1 -1
  39. data/doc/Compony/ModelFields/Association.html +1 -1
  40. data/doc/Compony/ModelFields/Attachment.html +1 -1
  41. data/doc/Compony/ModelFields/Base.html +1 -1
  42. data/doc/Compony/ModelFields/Boolean.html +1 -1
  43. data/doc/Compony/ModelFields/Color.html +1 -1
  44. data/doc/Compony/ModelFields/Currency.html +1 -1
  45. data/doc/Compony/ModelFields/Date.html +1 -1
  46. data/doc/Compony/ModelFields/Datetime.html +1 -1
  47. data/doc/Compony/ModelFields/Decimal.html +1 -1
  48. data/doc/Compony/ModelFields/Email.html +1 -1
  49. data/doc/Compony/ModelFields/Float.html +1 -1
  50. data/doc/Compony/ModelFields/Integer.html +1 -1
  51. data/doc/Compony/ModelFields/Percentage.html +1 -1
  52. data/doc/Compony/ModelFields/Phone.html +1 -1
  53. data/doc/Compony/ModelFields/RichText.html +1 -1
  54. data/doc/Compony/ModelFields/String.html +1 -1
  55. data/doc/Compony/ModelFields/Text.html +1 -1
  56. data/doc/Compony/ModelFields/Time.html +1 -1
  57. data/doc/Compony/ModelFields/Url.html +1 -1
  58. data/doc/Compony/ModelFields.html +1 -1
  59. data/doc/Compony/ModelMixin.html +1 -1
  60. data/doc/Compony/NaturalOrdering.html +1 -1
  61. data/doc/Compony/RequestContext.html +1 -1
  62. data/doc/Compony/Version.html +1 -1
  63. data/doc/Compony/ViewHelpers.html +1 -1
  64. data/doc/Compony/VirtualModel.html +1 -1
  65. data/doc/Compony.html +1 -1
  66. data/doc/ComponyController.html +1 -1
  67. data/doc/_index.html +97 -1
  68. data/doc/file.CHANGELOG.html +758 -0
  69. data/doc/file.README.html +25 -4
  70. data/doc/file.basic_component.html +314 -0
  71. data/doc/file.cookbook.html +189 -0
  72. data/doc/file.destroy.html +105 -0
  73. data/doc/file.dsl_reference.html +672 -0
  74. data/doc/file.edit.html +109 -0
  75. data/doc/file.example.html +291 -0
  76. data/doc/file.example_advanced.html +257 -0
  77. data/doc/file.feasibility.html +115 -0
  78. data/doc/file.form.html +195 -0
  79. data/doc/file.generators.html +89 -0
  80. data/doc/file.glossary.html +217 -0
  81. data/doc/file.gotchas.html +222 -0
  82. data/doc/file.index.html +135 -0
  83. data/doc/file.inheritance.html +136 -0
  84. data/doc/file.installation.html +115 -0
  85. data/doc/file.integrations.html +218 -0
  86. data/doc/file.intents.html +265 -0
  87. data/doc/file.internal_datastructures.html +129 -0
  88. data/doc/file.list.html +253 -0
  89. data/doc/file.maintaining.html +127 -0
  90. data/doc/file.model_fields.html +137 -0
  91. data/doc/file.nesting.html +237 -0
  92. data/doc/file.new.html +109 -0
  93. data/doc/file.ownership.html +98 -0
  94. data/doc/file.patterns.html +669 -0
  95. data/doc/file.pre_built_components.html +99 -0
  96. data/doc/file.resourceful.html +181 -0
  97. data/doc/file.show.html +158 -0
  98. data/doc/file.standalone.html +233 -0
  99. data/doc/file.virtual_models.html +117 -0
  100. data/doc/file.with_form.html +157 -0
  101. data/doc/file_list.html +160 -0
  102. data/doc/guide/cookbook.md +41 -0
  103. data/doc/guide/dsl_reference.md +155 -0
  104. data/doc/guide/example_advanced.md +209 -0
  105. data/doc/guide/generators.md +1 -1
  106. data/doc/guide/glossary.md +42 -0
  107. data/doc/guide/gotchas.md +125 -0
  108. data/doc/guide/maintaining.md +64 -0
  109. data/doc/guide/patterns.md +681 -0
  110. data/doc/guide/pre_built_components/edit.md +1 -1
  111. data/doc/guide/pre_built_components/index.md +64 -1
  112. data/doc/guide/pre_built_components/list.md +111 -7
  113. data/doc/guide/pre_built_components/show.md +57 -2
  114. data/doc/guide/pre_built_components/with_form.md +56 -9
  115. data/doc/guide/pre_built_components.md +7 -2
  116. data/doc/guide/standalone.md +16 -1
  117. data/doc/index.html +25 -4
  118. data/doc/integrations.md +61 -0
  119. data/doc/llms.txt +62 -0
  120. data/doc/top-level-namespace.html +1 -1
  121. data/lib/compony/component.rb +8 -3
  122. data/lib/compony/component_mixins/default/standalone/standalone_dsl.rb +32 -15
  123. data/lib/compony/component_mixins/default/standalone/verb_dsl.rb +11 -3
  124. data/lib/compony/component_mixins/resourceful.rb +30 -16
  125. data/lib/compony/components/destroy.rb +21 -1
  126. data/lib/compony/components/edit.rb +25 -1
  127. data/lib/compony/components/form.rb +63 -21
  128. data/lib/compony/components/list.rb +1 -1
  129. data/lib/compony/components/new.rb +25 -1
  130. data/lib/compony/components/with_form.rb +20 -5
  131. data/lib/compony/intent.rb +1 -1
  132. metadata +43 -1
@@ -0,0 +1,125 @@
1
+ [Back to the guide](/README.md#guide--documentation)
2
+
3
+ # Gotchas / anti-patterns
4
+
5
+ Known footguns, each with **symptom → cause → fix**. Skim before debugging.
6
+
7
+ ### 1. `standalone` without an explicit `path:`
8
+
9
+ - **Symptom:** `undefined method '..._comp_path'`, or no route generated for the component.
10
+ - **Cause:** `standalone` only emits a route when a `path:` is given.
11
+ - **Fix:** Always pass `standalone path: 'users/show/:id' do ... end`. A component with no
12
+ standalone is valid but must be nested in another component (has no URL).
13
+
14
+ ### 2. `render_intent` / `render_sub_comp` output not appearing
15
+
16
+ - **Symptom:** The button/list silently missing from the rendered page.
17
+ - **Cause:** Dyny does not auto-print return values. `render_intent` returns an HTML string.
18
+ - **Fix:** Wrap it: `concat render_intent(:edit, user)` (Dyny's equivalent of `<%= %>`).
19
+
20
+ ### 3. Overriding `respond` skips authorization
21
+
22
+ - **Symptom:** An endpoint is reachable without the expected permission check.
23
+ - **Cause:** `authorize` is evaluated inside the *default* `respond`. A custom `respond`
24
+ (especially the `nil`/all-formats one) replaces it.
25
+ - **Fix:** Re-check authorization yourself inside the custom `respond`, or keep a separate
26
+ default `respond` for the relevant format.
27
+
28
+ ### 4. `schema_field` with the foreign key name
29
+
30
+ - **Symptom:** Association param rejected by Schemacop / not assigned.
31
+ - **Cause:** Compony adds `_id` for associations automatically.
32
+ - **Fix:** Use the **association name**: `schema_field :author`, not `schema_field :author_id`.
33
+ Same for `field :author` in `form_fields`.
34
+
35
+ ### 5. Model without `label`
36
+
37
+ - **Symptom:** Errors or blank text when Compony renders titles/links for the model.
38
+ - **Cause:** Compony calls `model.label` for display everywhere.
39
+ - **Fix:** Implement `def label` on every Compony model (or have a `label` column).
40
+
41
+ ### 6. Forgetting to forward args in a custom `initialize`
42
+
43
+ - **Symptom:** `parent_comp`, `@data`, comp opts mysteriously `nil`; nesting broken.
44
+ - **Cause:** The base initializer wires essential state. Skipping `super` drops it.
45
+ - **Fix:** Call `super(*args, **kwargs, &block)` first, then set your own ivars. Prefer
46
+ putting logic in `setup` instead of overriding `initialize`.
47
+
48
+ ### 7. Reading a label without its block argument
49
+
50
+ - **Symptom:** `wrong number of arguments` from a label block.
51
+ - **Cause:** Resourceful components' label blocks take the model; non-resourceful take none.
52
+ - **Fix:** `label(User.first)` for resourceful; `label` (no arg) otherwise. At most one arg.
53
+
54
+ ### 8. `content :name` inside a block tries to render another component's block
55
+
56
+ - **Symptom:** Content block not found / unexpected output.
57
+ - **Cause:** Nested `content :name` only renders a block defined in the **same** component.
58
+ - **Fix:** To embed another component use `render_sub_comp`, not nested `content`.
59
+
60
+ ### 9. Multiple pages in one component
61
+
62
+ - **Symptom:** Tangled `standalone`/`verb`/`respond` tree, confusing routes.
63
+ - **Cause:** Extra `standalone` calls are for *companion* endpoints (AJAX tiles, autocomplete
64
+ JSON) of the *same* screen — not for separate pages.
65
+ - **Fix:** One screen = one component exposing one main route. Make another component for
66
+ another page.
67
+
68
+ ### 10. Resourceful component on a path without `:id`
69
+
70
+ - **Symptom:** `Couldn't find <Model> without an ID` (e.g. an Index at `/users`).
71
+ - **Cause:** Default `load_data` does `data_class.find(params[:id])`.
72
+ - **Fix:** Override `load_data { @data = User.all }` (or your scope) for collection/index
73
+ components.
74
+
75
+ ### 11. `redirect_to` with a hardcoded path
76
+
77
+ - **Symptom:** Links break after renaming/moving a component.
78
+ - **Cause:** Bypassing the intent system.
79
+ - **Fix:** Use `redirect_to Compony.path(:index, :users)` / `Compony.path(:show, @data)`.
80
+
81
+ ### 12. ActiveStorage attachment on a virtual model
82
+
83
+ - **Symptom:** Uploaded file not persisted for a `Compony::VirtualModel`.
84
+ - **Cause:** Virtual models aren't backed by a real table; the default `store_data` save
85
+ doesn't persist attachments.
86
+ - **Fix:** Override `store_data` to only validate (`@create_succeeded = @data.validate`) and
87
+ perform the real mutation/attachment in `on_created_respond`. See
88
+ [virtual_models.md](/doc/guide/virtual_models.md).
89
+
90
+ ### 13. `tailwindcss-rails` purges Compony styles
91
+
92
+ - **Symptom:** Compony component markup unstyled in production.
93
+ - **Cause:** Tailwind's unused-CSS purge doesn't scan component classes (their HTML isn't in
94
+ `app/views`).
95
+ - **Fix:** Safelist the classes, or don't use `tailwindcss-rails` with Compony (see
96
+ README "Caveats").
97
+
98
+ ### 14. Public endpoint still 401/redirecting
99
+
100
+ - **Symptom:** Webhook/public action blocked by app auth or CSRF.
101
+ - **Cause:** `skip_authentication!` alone doesn't remove CSRF, and `authorize` is still
102
+ mandatory.
103
+ - **Fix:** In the standalone: `skip_authentication!` + `skip_forgery_protection!`, and in
104
+ the verb `authorize { true }` (then validate a bearer token yourself).
105
+
106
+ ### 15. Hand-rolled endpoint where a pre-built CRUD component exists
107
+
108
+ - **Symptom:** A custom `Compony::Component` with manual `button_to`/standalone for
109
+ delete/edit/create, duplicating routing, authorization, confirmation UI, styling.
110
+ - **Cause:** Reaching for a bespoke component instead of the pre-built one.
111
+ - **Fix:** For CRUD use the pre-built parents (`Destroy`/`Edit`/`New`/`Show`/`Index`) and
112
+ point with `render_intent(:destroy, record)`. Reserve custom `Compony::Component`
113
+ standalones for genuinely non-CRUD actions (job dispatch, webhooks, multi-record ops).
114
+ Put a resourceful component in the family of the model it operates on, not the family
115
+ it is navigated from; pass parent context via path params.
116
+
117
+ ### 16. `attr_accessor` on a model for form-only fields
118
+
119
+ - **Symptom:** Virtual form fields declared as `attr_accessor` on the ActiveRecord model.
120
+ - **Cause:** Polluting the persistent model with form-only concerns.
121
+ - **Fix:** Use an `ActiveType::Record[Model]` (or `Compony::VirtualModel`) inner class on
122
+ the component with `ar_attribute` + `field`, and set `data_class` to it. See
123
+ [virtual_models.md](/doc/guide/virtual_models.md).
124
+
125
+ [Guide index](/README.md#guide--documentation)
@@ -0,0 +1,64 @@
1
+ [Back to the guide](/README.md#guide--documentation)
2
+
3
+ # Maintaining Compony
4
+
5
+ Conventions for contributors and AI assistants working **on the gem itself** (not apps
6
+ using it). Keeps docs, gemspec and the rendered API reference from drifting.
7
+
8
+ ## Every change
9
+
10
+ - **Behavior change → CHANGELOG.** Add a bullet under the top `# unreleased` heading in
11
+ [CHANGELOG.md](/CHANGELOG.md). If it breaks existing apps, add a `## Steps to take`
12
+ subsection with the migration (see prior entries for the format).
13
+ - **New/renamed DSL method → docs.** Update [dsl_reference.md](/doc/guide/dsl_reference.md)
14
+ (keep the `# DSL method` source marker) and add a YARD summary with
15
+ `@param`/`@return`/`@api` on the method.
16
+ - **Comments only / docs only is fine to note as such** in the CHANGELOG ("no behavior
17
+ change").
18
+
19
+ ## Releasing
20
+
21
+ 1. Bump the version in `lib/compony/version.rb`. Loading the Rakefile rewrites `VERSION`
22
+ from it; `.edge` marks an unreleased prerelease.
23
+ 2. Run `rake gemspec` — regenerates `compony.gemspec` (never hand-edit it; it says so).
24
+ 3. Move the `# unreleased` CHANGELOG block to a `# X.Y.Z` heading; start a fresh
25
+ `# unreleased`.
26
+ 4. Run `yard doc` and **commit the regenerated `doc/*.html`** — the rendered API
27
+ reference is committed and shipped in the gem (`s.files`), so stale HTML ships
28
+ otherwise.
29
+ 5. `bundle exec rubocop` clean.
30
+ 6. Tag / push / `gem build` per your release flow (`bundler/gem_tasks`).
31
+
32
+ ## Dependencies
33
+
34
+ - Hard deps and their constraints live **only** in the `:gemspec` task in
35
+ [`Rakefile`](/Rakefile). Change them there, run `rake gemspec`, and update the mirror
36
+ table in [integrations.md](/doc/integrations.md) in the same commit.
37
+ - Keep the README's stated Rails/Ruby support in sync with
38
+ `required_ruby_version` / the `rails` constraint — the gemspec is authoritative.
39
+
40
+ ## Documentation rendering
41
+
42
+ - `doc/*.html` is generated by YARD from `lib/` + the extra files listed in
43
+ [`.yardopts`](/.yardopts).
44
+ - **Adding a guide page?** Add its path to `.yardopts` (after the `-` separator) or it
45
+ will not appear in the rendered reference, then re-run `yard doc`.
46
+ - Markdown changes to already-listed guide pages still need a `yard doc` re-run + commit
47
+ to refresh the HTML.
48
+ - `yard doc` logs `Cannot resolve link to … from text:` for guide-to-guide Markdown links
49
+ and inline `<code>` in the guide pages. This is **expected and benign** — YARD tries to
50
+ treat them as Ruby code-object links. The pages render correctly and the links work on
51
+ GitHub. Do not rewrite guide cross-links to silence YARD. (Genuine broken `{Xref}` in
52
+ Ruby `lib/` comments are worth fixing; guide-Markdown link warnings are not.)
53
+
54
+ ## Patterns derived from real apps
55
+
56
+ - [patterns.md](/doc/guide/patterns.md) / [cookbook.md](/doc/guide/cookbook.md) are
57
+ **fully anonymized**: no app, business, author or domain-model names; neutral domain
58
+ (`Account`, `Order`, `LineItem`, `Document`); app-wrapper-only APIs excluded or
59
+ generalized (this is a public LGPL repo).
60
+ - Document the **secure** variant only. Never reproduce an insecure shape (e.g. a
61
+ capability token without expiry) even if that is what an app currently does — show the
62
+ hardened form and call out the requirement.
63
+
64
+ [Guide index](/README.md#guide--documentation)