ActiveRecord#attributes= with nested records

Given an ActiveRecord A, that belongs_to a B, which in turn belongs_to
a C, I can create a single form to edit all the attributes of these
nested records in one go, leading to a params hash with structure

{“a” => { “b” => { “c_attr1” => “x”, c_attr2" => “x” }, “b_attr” =>
“x” }, “a_attr” => “x” }

I thought code like this would work:

a =
a.b =
a.b.c =

a.attributes = params[:a]

It doesn’t: the attributes= tries to use normal assignment for all
elements of params, leading to an AssociationTypeMismatch (i.e. B
expected, got HashWithIndifferentAccess) when it tries to assign a
nested Hash to a nested AR. I thought it would detect a nested AR and
call its attributes= rather than plain =?

What is the best way to solve this?
Is there a reason why adding a little bit more intelligence to
attributes= wouldn’t work?

Thanks in advance,

On Jan 24, 2008, at 9:32 AM, Chris P. wrote:

call its attributes= rather than plain =?

What is the best way to solve this?
Is there a reason why adding a little bit more intelligence to
attributes= wouldn’t work?

How do you think this would work inside AR? It’s kind of not the way I
understand association proxies to work.

This info from the rdoc may be of use (note the part about
attr_protected), still I don’t know whether you will get the behavior
you want by assigning a hash:

Allows you to set all the attributes at once by passing in a hash with
keys matching the attribute names (which again matches the column
names). Sensitive attributes can be protected from this form of mass-
assignment by using the attr_protected macro. Or you can alternatively
specify which attributes can be accessed with the
attr_accessiblemacro. Then all the attributes not included in that
won’t be allowed to be mass-assigned.

I hadn’t considered attr_protected, or what would happen to has_many
collections. Should it be possible to assign to those via an
attributes hash? Probably not.

I suppose I expected it to work for my example because AR does a
reasonable job of providing a hash-like interface for accessing/
setting individual attriubutes, e.g.

a[:b][:b_attr] = “x”

and if a[:b] was really a hash, you would be able to assign it in one
go, or assign a nested hash to a in one go…

In essence, it’s easy to get a form helper to use a hash structure to
get/set values of nested AR attributes. It doesn’t seem to be so easy
to get those values back into the AR structure.

So what is the preferred way?

If I don’t try to mirror the structure, I can create variables to
point to each layer and use those in the form, e.g.


@a = a
@b = a.b
@c = a.b.c


<% form_for @a
<% fields_for @b
<% fields_for @c

Controller after post

a =[:a])
a.b =[:b])
a.b.c =[:c])

This seems a bit long-winded, although it does hide the structure from
the View…?

Checkout the complex forms series on It uses
this concept for setting one-to-many values.

On Jan 25, 12:19 am, Chris P. [email protected]


the View…?
I’ve never solved this particular problem but 37s did, and that’s –
as I understand it – what form_for was created to do.

Then in the controller, you could:

a = A.create(params[:a])
b = B.create(params[:b])

a << b
b << C.create(params[:c])

Again, I’m not writing real code here, so the may be redundant
and this doesn’t take failed validations or anything into account. You
might also consider delegating this work to the “master” model where
it might make more sense.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs