To understand the form rendering example that follows I posted the classes that are referenced and their associations below where a
User has many
Form‘s and a
Form has many
class User < ApplicationRecord has_many :forms end
class Form < ApplicationRecord belongs_to :user has_many :form_fields end
class FormField < ApplicationRecord belongs_to :form end
What I needed to do here was get one form rendered for the
Form object and a collection of forms rendered form the
FormFields object. The route the forms are rendered at are nested under
User at the
Form#edit controller action:
The edit action sets instance variables for
def edit @user = User.joins(forms: :form_fields).find(params[:user_id]) @form = @user.forms.find(params[:id].to_i) end
After the controller is called the edit template is rendered which renders two partials, one for forms form and a partial for the form fields form.
In the code example below the key thing to point out is the rendering of the form partial in the same directory, we pass that rendered partial a form and user which will be accessible within the template.
<h1>Edit: <%= @form.name %></h1> <%= render 'form', form: @form, user: @user %>
The below snippet is actual form file that was rendered in the previous example. We do two things here:
Render a form for the actual form. To do this we need to pass both the
@formto account for the nested route.
Render a collection of forms for the form fields. From the form object we get the collection
FormFieldsdata associated, which is another ActiveRecord object. During the iteration of those objects, we render the form partial for each form field and pass it the form_field object to build the form from.
<%= form_with(model: [@user, @form]) do |f| %> <%= f.label :name %> <%= f.text_field :name, value: @form.name %> <div class="actions"> <%= f.submit %> </div> <% end %> <% @form.form_fields.each do |form_field| %> <%= render 'form_fields/form', form_field: form_field %> <br /> <% end %>
This is the final rendered form_field partial, which utilizes the data passed into the form_field partial shown in the previous code snippet.
<%= form_with(model: form_field) do |form| %> <%= form.label :html_input_type %> <%= form.text_field :html_input_type, value: form_field.html_input_type %> <%= form.label :html_element_type %> <%= form.text_field :html_element_type, value: form_field.html_element_type %> <%= form.label :name %> <%= form.text_field :name, value: form_field.name %> <%= form.label :options %> <%= form.text_field :options, value: JSON.pretty_generate(form_field.options) %> <div class="actions"> <%= form.submit %> </div> <% end %>
If you followed along to the end you should now be able to view your forms at