Per my previous post, I’m trying to be better about recording “Duh” / “Aha” moments in my experiments with Rails to 1) improve my learning / general consumer-of-open-source-software habits, and 2) in hopes that I don’t make similar same silly mistakes again.
fields_for with a serialized
I’ve used plenty of nested forms recently, but always (and now, in retrospect, not always necessarily) with ActiveRecord-based
Today, I was adding a new attribute to an existing model, and wanted to add some attributes that would simply be attached to the model via a serialized field, rather than any sort of join (similar to the setup in this post).
I wanted to store a set of BillItems on each User, but since they would be fairly isolated from anything else in the database and be tied strictly to each User, I decided to just attach it to each User.
And because each User could theoretically have many BillItems, we’d want to ensure
:bill_items was serialized as an Array.
I was finding, though, frustratingly, that the following form was being generated incorrectly – only a single
bill_item field was represented in the form, and even when sanity checking by iterating over
bill_item records manually, the field markup was missing the indices necessary for the form to recognize each field as a separate form parameter. So when the template looked like this:
The output looked (sadly) like this:
What the docs missed out on saying (under One-to-many) is that: rather than the
projects_attributes= attributes writer method just being 1) recommended, 2) worth considering, and 3) available to be replaced by a
:projects were already an association on the model, it’s actually required for
fields_for to correctly nest the fields.
And, of course,
:bill_items not being a proper association, I wasn’t able to use the standard
accepts_nested_attributes_for helper and ran afoul of this. With the correct
*_attributes method defined, the form finally displays perfectly, so that
bill_items are passed through correctly, as an Array:
Lesson learned, and change committed.