DEV Community

Cover image for Complex Forms in Rails
CiaraMaria
CiaraMaria

Posted on • Updated on

Complex Forms in Rails

Rails offers all kinds of intuitive solutions for programmers, one of which is form helpers. In this post, I'll be breaking down the steps for creating a nested form - which is basically a form within a form. Formception.

When creating my first Rails project, I found myself searching for guidance on creating this type of form. While there are many sources that show you how to do this with a has_many association, I struggled to find examples for belongs_to. So, we will be working with a complex form for a joins table.

We're building a mood diary. We have two models to work with regarding our nested form: Entry and Emotion.

Entry is our joins table and so it's association is belongs_to :emotion, while Emotion has_many :entries.
When imagining the functionality of our form, we can conclude that we want to have the ability to create our Entry and either assign it an existing emotion or create a new one.

First, we want to use accepts_nested_attributes_for class method in our Entry model. This method defines an attributes writer for the specified association, in this case, Emotion.
Going along with the Rails penchant for convention over configuration, a good rule of thumb to remember when setting up nested forms is:
If the association 'belongs to' a singular model (e.g., emotion) we will maintain the singular form of reference. If the association 'has many' plural models we will maintain the plural form of reference throughout our code.

Now we will need to modify our declared permitted parameters to accommodate the nested attributes. Following our example, we will add this to our EntriesController. In the code below I have added a key for association attributes, where the association is the relationship you want to 'nest' into your form. Put simply, it's the one you added to accepts_nested_attributes_for. This key holds the specified association's attributes that we want passed in.

Note: In this example, :emotion_id is included outside of emotion_attributes: - As shown in the Rails guide we can also use:

def entry_params
    params.require(:entry).permit(:content, emotion_attributes: [
         :id, :name
    ])
end
Enter fullscreen mode Exit fullscreen mode

Finally, we are ready to create our form!

The magic happens within the fields_for tag which, when associated with accepts_nested_attributes, renders a block once for every element of the association. We then use the build_association method which instantiates the object from the passed attributes and sets a link through the foreign key.

Note: Pay close attention to build_association method. Not to be confused with collection.build, which instantiates an object from the passed attributes and creates a foreign key. The latter is a method made accessible when declaring a has_many association.

Our final product (plus a bit of CSS) looks like this, with the option to select or create an emotion:

Top comments (2)

Collapse
 
leastbad profile image
leastbad

I didn't know about the build_association method. TIL!

If you're working with remote forms, you might find Optimism pretty cool.

Collapse
 
mariaverse profile image
CiaraMaria

Very cool! Thanks for sharing.