Mastering the Art of Nested Attributes in Rails

Mastering the Art of Nested Attributes in Rails

·

2 min read

This article was written with the help of AI.

Have you ever found yourself in a situation where you needed to create multiple records at once in Rails? Maybe you have a form that allows a user to create a new record and its associated records in one go. Or maybe you're importing data from a CSV file and need to create multiple records with nested attributes. In these cases, nested attributes can be a powerful tool to help you efficiently create records in bulk. Nested attributes allow you to save attributes on associated records through the parent record. In other words, you can create or update records on associated models at the same time you create or update the parent model. This can save you a lot of time and effort, especially when dealing with complex data structures. Here's an example of how you can use nested attributes in Rails:

class Order < ApplicationRecord
  has_many :line_items
  accepts_nested_attributes_for :line_items
end

class LineItem < ApplicationRecord
  belongs_to :order
end

In this example, an order has many line items, and we're using accepts_nested_attributes_for to allow the order to accept attributes for its associated line items.

Now, let's say we have a form that allows a user to create a new order and its associated line items in one go. Here's what the form might look like:

<%= form_with(model: @order, local: true) do |form| %>
  <%= form.label :name %>
  <%= form.text_field :name %>

  <%= form.fields_for :line_items do |line_item_fields| %>
    <%= line_item_fields.label :product %>
    <%= line_item_fields.text_field :product %>

    <%= line_item_fields.label :quantity %>
    <%= line_item_fields.number_field :quantity %>
  <% end %>

  <%= form.submit %>
<% end %>

Note the use of fields_for to create fields for the associated line items. This tells Rails to create fields with names like order[line_items_attributes][0][product] and order[line_items_attributes][0][quantity] that can be used to create or update the associated line items.

In the controller, we can use strong parameters to permit the nested attributes:

class OrdersController < ApplicationController
  def create
    @order = Order.new(order_params)

    if @order.save
      redirect_to @order
    else
      render :new
    end
  end

  private

  def order_params
    params.require(:order).permit(:name, line_items_attributes: [:product, :quantity])
  end
end

Here, we're using permit to allow the name attribute for the order and the product and quantity attributes for the associated line items.

And that's it! With nested attributes, you can easily create and update associated records in Rails without a lot of extra code. Give it a try and see how it can simplify your data handling.

I hope you found this post useful!