I am writing this blog for myself more than for the readers, so bare with me. Today I am going to try and explain Basic Nested Forms and what I am learning.
So what is a Nested Form?
How I would describe a nested form, and I could be completely wrong so correct me if I am, a nested forms allows a user to create or update a database for multiple models at once. For example, lets pretend you want to create a recipe book that accepts ingredients and your schema looked like this:
ActiveRecord::Schema.define(version: 20160114135651) do
create_table "ingredients", force: :cascade do |t|
t.string "item_name"
t.string "amount"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "recipe_id"
end
create_table "recipes", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
end
You would have to create an association to show that an ingredient belongs to a recipe and that a recipe can have many ingredients. You would do that by adding the following to your ingredient model:
class Ingredient < ActiveRecord::Base
belongs_to :recipe
end
and this piece of code to your recipe model:
class Recipe < ActiveRecord::Base
has_many :ingredients
accepts_nested_attributes_for :ingredients
end
Now when you look at the code above, did your eyebrow raise?
Well great because mine did too!
What does accepts_nested_attributes_for :ingredients
mean?
According to the documentation, nested attributes allow you to save attributes on associated records through the parent.
As usual, I wish people who wrote these docs wrote in English, accepts_nested_attributes_for :ingredients
allows us to reference the attributes for ingredients in our recipe model/forms.
So, how do we reference the ingredients attributes in the form? Well, like this:
<%= form_for @recipe do |f| %>
<%= f.label :name %>
<%= f.text_field :name%><br>
<%= f.fields_for :ingredients do |i| %>
<%= i.label :item_name %>
<%= i.text_field :item_name %><br>
<%= i.label :amount %>
<%= i.text_field :amount %><br>
<% end %>
<%= f.submit %>
<% end %>
So, it allows you to reference the ingredients in the recipe form, GREAT! However, in the current state there will be nothing in the fields, we must first create an instance of recipe and ingredients. This brings us to the final step, we must update the recipe controller:
def new
@recipe = Recipe.new
@recipe.ingredients.build(name: "Ingredient 1")
@recipe.ingredients.build(name: "Ingredient 2")
end
def create
recipe = Recipe.create(recipe_params)
redirect_to recipes_path
end
private
def recipe_params
params.require(:recipe).permit(
:title,
ingredients_attributes: [
:name,
:quantity
]
)
end
The new
method creates a new recipe instance to be referenced in the form and the .build
returns a new object of the collection type that has been instantiated with attributes and linked to this object, but have not yet been saved. You can pass an array of attributes hashes, this will return an array with the new objects.
So now, the form will know what to reference by using that new instance of recipe and ingredients created.
The create
method creates a recipe and that accepts the recipe_params
method.
The recipe_params
method allows us to choose the ingredients and recipe attributes that should be permitted for updating and allows us to prevent accidentally exposing that which shouldn't be exposed.
This is the very basics of Nested forms and I hope this helps someone.
As always, thanks for reading.
Sincerely,
Brittany
Top comments (0)