Jonathan Bennett

One Form, Multiple Objects with Rails Magic

If you’ve ever needed to handle complex object relationships with a single form, accepts_nested_attributes might be exactly what you’re looking for.

accepts_nested_attributes creates an attribute on the host object that, by default, handles mass assignment for a guest object.

For example, if a User class has a Profile via a has_one relationship, adding accepts_nested_attributes_for :profile to the User class with create a profile_attributes= method. At its core, this method looks like:

def profile_attributes=(values)  
  profile.assign_attributes(values)  
end  

Of course, Rails adds its magic, but this is the general idea.

Linking Forms and Params

When building forms, fields_for helps structure nested data automatically:

<%= form_with model: user do |form| %>  
  <%= form.fields_for :profile_attributes do |profile_form| %>  
	<%= profile_form.text_field :name %>  
	<!-- Generates: <input name="user[profile_attributes][name]" /> -->  
  <% end %>  
<% end %>  

This ensures your form inputs map directly to nested attributes in your models.

In your controller, update the params to allow nested attributes:

class UsersController < ApplicationController  
  def update  
	user.assign_attributes(user_params)  
  end  

  def user_params  
	params.require(:user).permit(:stuff, profile_attributes: [:name, :description])  
  end  
end  

And there you have it! With a few lines of code, accepts_nested_attributes helps you build intuitive forms for complex relationships.

Come back tomorrow for common pitfalls and how to avoid them!