Reputation: 1481
I understand we can use fields_for to create a subsection of fields for nested attributes. However, I would like to split them through the form. How can I do this?
For instance:
Suppose I have a model foo with a nested bar model, like this:
class Foo < ApplicationRecord
has_many :bars
accepts_nested_attributes_for :bars
end
A general view would be something like this:
<%= form_for @foo do |f| %>
<!-- foo fields -->
<%= f.fields_for :bars do |f_bar| %>
<!-- bar fields -->
<% end %>
<%= f.submit "Submit" %>
<% end %>
But for aesthetics reasons, I don't want all the bars
agglomerated at one place. I would like to do something like:
<%= form_for @foo do |f| %>
<!-- foo fields -->
<%= f.fields_for :bars do |f_bar| %>
<!-- bar fields of one bar -->
<% end %>
<!-- other foo fields -->
<%= f.fields_for :bars do |f_bar| %>
<!-- bar fields of another bar -->
<% end %>
<!-- The previous repeats many more times in a non predictable way -->
<%= f.submit "Submit" %>
<% end %>
So it would be perfect for me if I didn't have to show all the bars
at once. Somebody knows how to that?
Upvotes: 2
Views: 1070
Reputation: 1481
So, it happens that all I needed was make fields_for
show only one instance per time.
I discovered that fields_for
lets you specify a particular object to render the fields. So, I just created a counter and added one @foo.bars[counter]
per time and it magically worked, it was something like this :
<% counter = 0 %>
<%= form_for @foo do |f| %>
<!-- foo fields -->
<%= f.fields_for :bars, @foo.bars[counter] do |f_bar| %>
<!-- bar fields of one bar -->
<% end %>
<% counter+=1 %>
<!-- other foo fields -->
<%= f.fields_for :bars, @foo.bars[counter] do |f_bar| %>
<!-- bar fields of another bar -->
<% end %>
<% counter+=1 %>
<!-- The previous repeats many more times in a non predictable way -->
<%= f.submit "Submit" %>
<% end %>
Upvotes: 4
Reputation: 1569
You can use the second param of fields_for and pass a scope:
class Bar < ApplicationRecord
belongs_to :foo
scope :some_a,->{where(conditions)}
scope :some_b,->{where(conditions)}
end
In your forms
<%= form_for @foo do |f| %>
<%= f.text_field :foo_attr %>
<%= f.fields_for :bars, @foo.bars.some_a do |b| %>
<%= b.hidden_field :other_bar_attr %>
<%= b.text_field :bar_attr %>
...
<% end %>
<%= f.fields_for :bars, @foo.bars.some_b do |b| %>
<%= b.hidden_field :other_bar_attr %>
<%= b.text_field :bar_attr %>
...
<% end %>
<%= f.submit %>
<% end %>
You can use the hidden input for setting default values that are used in the scopes.
UPDATE
If you need to use a multiple instances of fields_for
in your form, you can do something like this
In the controller set an array for the scoped objects, an example could be:
class SomeController < AP
def some_action
@var_to_the_form = []
(1..well_know_quantity).each do |value|
@var_to_the_form << Model.where(conditions)
end
end
end
And your form has to be as follows
<% @var_to_the_form.each do |records| %>
<%= f.fields_for :bars, records do |b| %>
<%= b.hidden_field :other_bar_attr %>
<%= b.text_field :bar_attr %>
...
<% end %>
<% end %>
The important part is to know how to set the records you are passing to the view.
Upvotes: 1