Forms for New Instances in Rails
Recently I’ve been spending a fair amount of time in this area of rails, and much of that time was spent learning as opposed to executing; so I felt imparting some of my newly found knowledge could save someone else a few hours as they slog through the same experience. (Looking at you, Bootcampers).
Forms are just that, a form that a user can fill out on an application. Typically when we think about forms we think a doctor’s office or a survey but we are inputting information into forms constantly. While I’m writing this article I am putting data into a text_area
variable. Filling out the title was most likely a text_field
variable, which is very similar to area except for shorter sentences like names, mantras or titles. Below is a look at some of the different variables in forms and how they are represented on screen.
The above are examples of where a user inputs data manually, but what if we’d like to choose from a list? That’s where collection_select
and collection_check_boxes
come in handy. These can be a little bit trickier but are integral to a good experience on a website.
In this example I’m using something from my personal page. I am the user
, and repos denote my GitHub repositories (kind of a bad example) but let’s say I wanted to add a repo to an instance of a user
. To break it down:
:repos
are part of the has_many relationship for a the user
and we simply have to permit it in our strong params. Code is as follows:
private def user_params
params.require(:user).permit(:name, :repos)
endend
For this particular example we are only allowing one even though it is a one-to-many relationship.The next helper method allows us to fix that, and choose from many.
Repo.all
are the choices we can choose from. Obviously we want a dropdown menu of all of the possible repos, so we call .all
on the Repo
class. Note that best practice says to set @repos = Repo.all and call @repos on the form.
:id
and :url
are attributes from the Repo
class, :url
is in the display position being the furthest to the right and :id
is in the value position. It looks like this on the web application:
Similar to collection_select
we can do collection_check_boxes
which allows for multiple selections as opposed to one. This is a much better choice when you have a has_many
relationship. Note that this can get a little bit tougher when you’re doing a many-to-many relationship. The code is essentially the same in the form_for
. The major changes are in the model/controller. Below is the form.
<%=form_for @user do |f| %>
<%=f.label "Name"%>
<%=f.text_field :name%><br>
<%=f.label "Repos"%><br>
<%=f.collection_check_boxes :repo_id, Repo.all, :id, :url %>
<%=f.submit%>
<%end%>
It took me a little while to wrap my head around this part. Now that we’re being passed an array, we need to add the ability to accept nested attributes to the User
class, the code looks as follows:
class User < ApplicationRecord
has_many :repos
accepts_nested_attributes_for :repos
end
The user controller now needs to permit an array for repos
as well, and we need to change the create method in the controller.
privatedef user_params
params.require(:user).permit(:name, repos:[])
end
The controller will need to iterate through the chosen id’s from the application’s user input, find them from the Repo class, and then shovel into the user.repos
array.
def create
@user = User.create(name: user_params[:name]) user_params[:repos].each {|repo| @user.repos << Repo.find_by(id:
repo) }
redirect_to @user
end
The final display will show all of the check boxes, so if you have a large pool to choose from, it may not be the best solution for starting out. I’d recommend looking into how to make the check boxes scrollable to allow for a better visual experience.
Since you will often times be using a similar structure for forms there is a way to reuse the same form through partials. The way to do this is to navigate to views and create a new view called _form.html.erb
. Then, in any other view you can simply call it through using <%= render ‘form’ %>
and it will save you having to rebuild the same code for new/edit.
To top off the form all you must do is add f.submit
and your form will be done. Whether creating new instances or editing ones, forms will come in handy with making the foundation of a website or application!