This post provides references to the code changes that need to be made to a scaffolded rails app in order to render a form for the resources. In the application I am providing the example from those resources are User and Form, where a form is rendered for a user. This is a survey rendering application, similar to TypeForm or SurveyMonkey.
This post will use the
form#edit action as an example but this can be applied to any of the resources.
Generating the scaffold
For those that want to code along with the post, you can start by creating a new rails application and generating the following two scaffolds:
rails g scaffold Form rails g scaffold User
This will create all of the resources needed to create and render forms and users, but we will make changes to the generated files to account for forms being nested within users.
Creating the tables and ActiveRecord relationships
To establish the relationships between the Form and User I added a reference to the users table in the form
create_table. Adding the reference requires the users table to exist before running the migration:
class CreateForms < ActiveRecord::Migration[6.1] def change create_table :forms do |t| t.references :user, index: true, null: false t.string :name t.timestamps end end end
User models add the
has_many associations appropriately:
class Form < ApplicationRecord belongs_to :user end
class User < ApplicationRecord has_many :forms end
Update routes to be nested
Update the routes file so
:forms are scoped under
:users because in this system a
Form will only exist under the context of a
User. This will also update the url helpers rails providers, which we will need to update references to later in the post.
resources :users do resources :forms end
rails routes command to see the changes to the routes definitions. For our edit example the new url is:
FormsController an update needs to be made to get form for a specific user. Since the route to access the
edit action is
/users/:user_id/forms/:id/edit we now have the
id (from_id) available to us as parameters to query for data.
edit example below we query for the user first and then filter the forms to find the correct resource. Setting the
@user variables will give us access to them in the view template:
class FormsController < ApplicationController before_action :set_user, only: %i[ edit ] def edit @form = @user.forms.find(params[:id].to_i) end private def set_user @user = User.find(params[:user_id]) end end
Updating views for FormsController#edit
When generating the scaffold for
Form you an edit template was created for you that looks similar to this:
<h1>Editing Form</h1> <%= render 'form', form: @form %> <%= link_to 'Show', @form %> | <%= link_to 'Back', forms_path %>
Since the forms were updated to be nested, we will need to account for two changes:
- The new url path helpers
- The added data needed for the form to render
After the updates the new
edit.html.erb will look like the below code example. The links were updated with the correct url paths and the data we provide to the form partial is accounted for.
<h1>Editing Form</h1> <%= render 'form', form_and_user: [@user, @form] %> <%= link_to 'Show', user_form_path(@form) %> | <%= link_to 'Back', user_forms_path %>
Finally update the references in the form partially to account for the changed parameter name as the example below illustrates:
Orginal form partial:
<%= form_with(model: form) do |form| %> # form elements <% end %>
Updated form partial:
<%= form_with(model: form_and_user) do |form| %> # form elements <% end %>
After making these updates you should be able to navigate to
Thanks for tuning in! I hope you found this post helpful today.