Non-ActiveRecord::Base serialized has_many attributes in a nested form

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.

This post: `fields_for` with a serialized `has_many` relationship

I’ve used plenty of nested forms recently, but always (and now, in retrospect, not always necessarily) with ActiveRecord-based has_many relationships.

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 accepts_nested_attributes_for if :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.

Let me know what you think on Twitter.