I recently built a form with nested models. It works, but want to know if what I did is best practice and how I can refactor it.
We have Posts with Tags. From the user’s perspective on the Post form they had a field where they could start typing into the Tag field and it would offer them existing tags to select, or it would allow them to type up a new tag word. The user would be able to add multiple tags this way.
For the front end I used the Select2 js library, which works well.
I created a PostTag
model to record the association between Posts and Tags.
In the Post model I added: accepts_nested_attributes_for :tags, allow_destroy: true
.
So far so good, however the controller for Post is quite complicated.
The params passed on the controller is a challenge to process, because the params were inconsistent. If the tag already exists, the params would be integers of tag ids wrapped into a string (ex. “3”), but if the tag was new it would be a straight string (ex. “history”).
I’m not sure if it’s the correct way to do it, but I basically did this:
- I would cycle through all the parameters and find the param called
tags_attributes
. - Take the array of values (tags) within this and cycle through them as well.
- Identify if the param value is NOT an integer. This means it’s a new tag word.
- If so, I would create a tag in the database, and then replace the tag word within the params with the id of the newly created tag.
- Finally I created the Post with the cleaned up parameters, which now includes the nested tags through PostTag.
I feel like there has to be a more elegant solution and I shouldn’t have to hack the controller this way to create new tags, but I could be wrong.
Thanks for reading and let me know what you think!