Rails: accepts_nested_attributes_for
For my Capstone Project with Flatiron School I was challenged to discover and implement methods outside of the core curriculum. In my previous projects, some of the functionality of the forms and submissions could have been simplified if I implemented accepts_nested_attributes_for. Since this was beyond the scope of my understanding, I did not incorporate it at that time. For my final project, I decided to dive in to this method and use it a little.
I highly suggest checking out ActiveRecord::NestedAttributes for a deeper understanding and more advanced ways of incorporating this into a project. My usage just scratches the surface of how powerful this can be.
What are Nested Attributes?
accepts_nested_attributes_for in ActiveRecord allows nested information to be created and saved through an associated relationship. Primarily information for a child can be created and saved simultaneously with the creation of the parent. Basically, this already makes sense and is logical, but this aspect is turned off by default. When accepts_nested_attributes_for is declared in a model the autosave is turned on and an attribute writer is generated which is named for the association.
In my previous project, I built a Personal Library SPA (for blog and video click here), where a user had the ability to add Genres and Books to their library. When adding a book, there was a dropdown menu of all possible genres. A user could put in information for a new book and create it as long as the genre they wanted was already saved in the backend. If they were trying to add a book to a genre that didn’t exist, they had to go to a separate form on the page, add a new genre to the list, return to the add a book form and then complete the form again (since the desired genre would now be listed). It’s not the worst thing in the world, but it’s multiple steps for a simple process. It would be easier, if the dropdown menu of genres enabled the user to “Add New Genre” and send in the data for the new genre at the same time as the new book. This is when accepts_nested_attributes_for could come in handy. It just makes the process simpler by removing a bunch of unnecessary steps.
My Current Project:
In building a Maintenance Tracker Application that enables users to personalize their site, the user and initial design information need to be generated at the same time. The site styling is dependent on the user having design information already established in the backend. I wanted all of this to be possible, because I wanted the user to be able to personalize their design at any time through a settings menu. (I configured design personalization using Styled-Components. See blog here for more detail.)
First, in the User model, I indicated that the User accepts_nested_attributes_for :designs. As mentioned above, this unlocked the create and save aspect of the association and generated an attribute writer: designs_attributes = (attributes).
When a user creates a new account, they complete a controlled sign up form. By completing the form, the user fills the username, password, and password_confirmation in the userObj as seen below:
The key designs_attributes: is a nested object within an array that I have pre-filled with the default design template for the site.
Important to note: designs_attributes had to be an object within an array [{}]. In the backend, when establishing the permitted params, each symbol correlates to a key in the object as sent from the frontend. So in the strong params in the backend, designs_attributes is not a symbol, it is a hash full of symbols that are permitted.
When the user clicks submit, userObj is sent via a POST fetch to the backend to create a new user, create a design associated with that user, and log the user into a session.
I used strong params for an added layer of protection. This also enabled me to specify what parameters are permitted in the create method. desings_attributes is not a symbol, rather it is a hash full of the symbols that are permitted.
So, username, password, and password_confirmation all come directly from the userObj as sent from the front end. designs_attributes: is the nested designs array from the userObj as sent from the front end through the POST fetch.
By doing this all in one step, when a new user is created, their design template is set to the default as specified in the designObj from the front end.
As mentioned above, I would encourage further reading into nested attributes ActiveRecord::NestedAttributes.