form_for conveniently uses “record identification” to figure out the correct URL based on the model:
It’s also used to figure out the HTTP verb, the field name prefixes, HTML classes and HTML id.
So this form would POST to
admin_items_path for a new record, or PUT to
admin_item_path(@item) for an existing record.
But it can break when you use STI (Single Table Inheritance).
1 2 3
1 2 3
You want this form to PUT to
admin_item_path(@item) but Rails will PUT to the non-existent
The Rails form helper guide says you can’t rely on record identification with STI.
You can, though, with some fiddling. This is what I just did:
1 2 3 4
#becomes changes the
SpecialItem to an
Item for the benefit of the record identification.
But then the form will have a plain
Item, so our
type dropdown won’t pre-select “SpecialItem”. So to fix that, we restore the form object on line 2.
#becomes mutates the attributes inside the original
@item, we must use
#becomes again on line 2.
My first attempt was to do
@item.dup.becomes(Item) on line 1 so the
@item is untouched. But that breaks the form’s
Whatever you go with, make sure to test your forms, as this is fragile territory.