Skip to content

Commit 5410179

Browse files
jonasjabarigitbook-bot
authored andcommitted
GitBook: [main] 64 pages and 6 assets modified
1 parent 5e3ccfe commit 5410179

File tree

6 files changed

+56
-35
lines changed

6 files changed

+56
-35
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1+
---
2+
description: Added in 2.1.0
3+
---
4+
15
# Nested Forms
26

37
Matestack provides functionality for reactive nested forms.
48

59
This works in conjunction with rails' `accepts_nested_attributes_for`. From the rails documentation on [nested attributes](https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html):
610

7-
> Nested attributes allow you to save attributes on associated records through the parent. By default nested attribute updating is turned off and you can enable it using the accepts_nested_attributes_for class method. When you enable nested attributes an attribute writer is defined on the model.
8-
9-
There is a little bit of setup required to enable this. There's a need for `accepts_nested_attributes_for`, `index_errors` on a models' `has_many` associations and an ActiveRecord patch.
11+
> Nested attributes allow you to save attributes on associated records through the parent. By default nested attribute updating is turned off and you can enable it using the accepts\_nested\_attributes\_for class method. When you enable nested attributes an attribute writer is defined on the model.
1012
13+
There is a little bit of setup required to enable this. There's a need for `accepts_nested_attributes_for`, `index_errors` on a models' `has_many` associations and an ActiveRecord patch.
1114

12-
Consider the following model setup, which is the same model found in the dummy app in the spec directory (active in this dummy app):
15+
Consider the following model setup, which is the same model found in the dummy app in the spec directory \(active in this dummy app\):
1316

1417
```ruby
1518
class DummyModel < ApplicationRecord
@@ -29,14 +32,13 @@ Note the `has_many :dummy_child_models, index_errors: true` declaration in the `
2932

3033
Normally with rails, when rendering forms using Active Record models, errors are available on individual model instances. When using `accepts_nested_attributes_for`, error messages sent as JSON are not as useful because it is not possible to figure out which associated model object the error relates to.
3134

32-
From rails 5, we can add an index to errors on nested models. We can add the option `index_errors: true` to has_many association to enable this behaviour on individual association.
33-
35+
From rails 5, we can add an index to errors on nested models. We can add the option `index_errors: true` to has\_many association to enable this behaviour on individual association.
3436

3537
## ActiveRecord Patch
3638

3739
Matestack nested forms support requires an ActiveRecord patch. This is because `index_errors` does not consider indexes of the correct existing sub records.
3840

39-
See rails [issue #24390](https://github.com/rails/rails/issues/24390)
41+
See rails [issue \#24390](https://github.com/rails/rails/issues/24390)
4042

4143
Add this monkey patch to your rails app
4244

@@ -58,76 +60,96 @@ module ActiveRecord
5860
end
5961
```
6062

63+
## Controller Setup
64+
65+
Adjusting strong params for nested form support does not differ from what needs to be done when using classsic Rails forms, e.g.:
66+
67+
```ruby
68+
def dummy_model_params
69+
params.require(:dummy_model).permit(
70+
:title,
71+
dummy_child_models_attributes: [:id, :_destroy, :title]
72+
)
73+
end
74+
```
75+
6176
## Example
6277

6378
```ruby
6479
class ExamplePage < Matestack::Ui::Page
6580

6681
def prepare
6782
@dummy_model = DummyModel.new
83+
# optional: build new instances before render:
6884
@dummy_model.dummy_child_models.build(title: "init-value")
6985
@dummy_model.dummy_child_models.build
7086
end
7187

7288
def response
89+
# use a normal form config, nothing new here
7390
matestack_form form_config do
74-
form_input key: :title, type: :text, label: "dummy_model_title_input", id: "dummy_model_title_input"
91+
form_input key: :title, type: :text, label: "dummy_model_title_input"
92+
93+
# use all kind of input components for the parent model here!
7594

7695
@dummy_model.dummy_child_models.each do |dummy_child_model|
77-
dummy_child_model_form dummy_child_model
96+
dummy_child_model_form(dummy_child_model)
7897
end
7998

99+
# optional!
100+
# lives outside of form_fields_for
80101
form_fields_for_add_item key: :dummy_child_models_attributes, prototype: method(:dummy_child_model_form) do
81-
# type: :button is important! otherwise remove on first item is triggered on enter
102+
# type: :button is important! otherwise form submission may be triggered when adding an item.
82103
button "add", type: :button
83104
end
84105

85-
form_fields_for_remove_item do
86-
# id is just required in this spec, but type: :button is important! otherwise remove on first item is triggered on enter
87-
button "remove", ":id": "'remove'+nestedFormRuntimeId", type: :button
88-
end
89-
90-
button "Submit me!"
91-
92-
toggle show_on: "success", hide_after: 1000 do
93-
plain "success!"
94-
end
95-
toggle show_on: "failure", hide_after: 1000 do
96-
plain "failure!"
97-
end
106+
button "Submit me!", type: :submit
98107
end
99108
end
100109

110+
# use a partial for all dummy child model forms
111+
# used for existing child models or as a 'prototype' form for new child models
112+
# when called from form_fields_for_add_item prototype, the first param is nil
101113
def dummy_child_model_form dummy_child_model = DummyChildModel.new
102114
form_fields_for dummy_child_model, key: :dummy_child_models_attributes do
115+
# do not use IDs for input fields!
116+
# IDs are assigned automatically in order to have unique IDs for each input
103117
form_input key: :title, type: :text, label: "dummy-child-model-title-input"
118+
119+
# use all kind of input components for the child model here!
120+
121+
# optional!
122+
# has to be placed within a form_fields_for component
104123
form_fields_for_remove_item do
105-
# id is just required in this spec, but type: :button is important! otherwise remove on first item is triggered on enter
106-
button "remove", ":id": "'remove'+nestedFormRuntimeId", type: :button
124+
# type: :button is important! otherwise form submission may be triggered when removing an item.
125+
button "remove", type: :button
107126
end
108127
end
109128
end
110129
end
111130
```
112131

113-
### Dynamically Adding Nested Items
132+
### Dynamically Adding Nested Items \(Optional\)
114133

115-
As in the example above, you can dynamically add nested items. As the comment in the code suggests `type: :button` is important, otherwise remove on first item is triggered on enter.
134+
As in the example above, you can dynamically add nested items. As the comment in the code suggests `type: :button` is important, otherwise form submission may be triggered when removing an item.
116135

117136
```ruby
137+
# lives outside of a form_fields_for component!
118138
form_fields_for_add_item key: :dummy_child_models_attributes, prototype: method(:dummy_child_model_form) do
119-
# type: :button is important! otherwise remove on first item is triggered on enter
120-
button "add", type: :button
139+
# type: :button is important! otherwise form submission may be triggered when removing an item
140+
button "add", type: :button
121141
end
122142
```
123143

124-
### Dynamically Removing Nested Items
144+
### Dynamically Removing Nested Items \(Optional\)
125145

126-
As in the example above, as well as dynamically adding items, you can dynamically remove nested items. Again, important: `type: :button` is important, otherwise remove on first item is triggered on enter.
146+
As in the example above, as well as dynamically adding items, you can dynamically remove nested items. Again, important: `type: :button` is important, otherwise form submission may be triggered when adding an item.
127147

128148
```ruby
149+
# has to be placed within a form_fields_for component!
129150
form_fields_for_remove_item do
130-
# id is just required in this spec, but type: :button is important! otherwise remove on first item is triggered on enter
131-
button "remove", ":id": "'remove'+nestedFormRuntimeId", type: :button
151+
# type: :button is important! otherwise form submission may be triggered when adding an item.
152+
button "remove", type: :button
132153
end
133154
```
155+

docs/getting-started/concepts-rails-integration.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Based on a strong foundation - Rails with all the sugar you love - Matestack ena
1212

1313
**which leads to beautiful reactive web UI implemented in pure Ruby:**
1414

15-
![](../.gitbook/assets/image%20%289%29%20%281%29%20%283%29%20%283%29%20%281%29.png)
15+
![](../.gitbook/assets/image%20%289%29%20%281%29%20%283%29%20%283%29%20%283%29%20%281%29.png)
1616

1717
yielding following advantages:
1818

docs/getting-started/quick-start.md

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ _This guide utilizes the full power of Matestack and uses `matestack-ui-core` as
1414
The code for this twitter-clone is available in [this repository](https://github.com/matestack/twitter-clone).
1515
{% endhint %}
1616

17-
1817
### Setup
1918

2019
* [x] Create a new Rails app and install some dependencies:

0 commit comments

Comments
 (0)