Active Record: Nested attributes
I recently learnt about quite a neat feature of Active Record called nested attributes which allows you to save attributes on associated records of a parent model.
It’s been quite useful for us as we have a few pages in our application where the user is able to update models like this.
We would typically end up with parameters coming into the controller like this:
class FoosController < ApplicationController
def update
# params = { :id => "1", :foo => { :baz => "new_baz", :bar_attributes => { :value => "something" } } }
Foo.update_instance(params[:id], params[:foo])
...
end
end
Our original implementation of 'update_instance' looked like this:
class Foo < ActiveRecord::Base
has_one :bar
class << self
def update_instance(id, attributes_to_update)
instance = Foo.find(id)
instance.attributes = attributes_to_update
instance
end
end
end
Unfortunately when we execute that code the 'bar' association gets completely removed because we didn’t specify the id of 'bar' when we were updating the attributes.
We need to change the code slightly to make sure it doesn’t do that:
class Foo < ActiveRecord::Base
has_one :bar
class << self
def update_instance(id, attributes_to_update)
instance = Foo.find(id)
attributes_to_update[:bar_attributes][:id] = instance.bar.id
instance.attributes = attributes_to_update
instance
end
end
end
It now works as we’d expect.
There’s other cool stuff that you can do with nested attributes described on the documentation page if you have 'has_many' associations but for now we’re just using the simpler 'has_one'.
About the author
I'm currently working on short form content at ClickHouse. I publish short 5 minute videos showing how to solve data problems on YouTube @LearnDataWithMark. I previously worked on graph analytics at Neo4j, where I also co-authored the O'Reilly Graph Algorithms Book with Amy Hodler.