I’m trying to create a database with two types of data.
1) Apartment buildings with their own attributes (ex. address)
2) Units (belonging to buildings) with their own attributes (ex. price, size)
I was wondering if I could have a page with a form for both databases?
Ex. A form to create a new building, and add the new unit information directly on the page.
<%= form_for(@building) do |f| %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :address %>
<%= f.text_field :address %>
<%= f.label :contact %>
<%= f.email_field :contact %>
<br>
<%= form_for(@unit) do |f| %>
<%= f.label :bedrooms %>
<%= f.text_field :bedrooms %>
<%= f.label :price %>
<%= f.text_field :price %>
<%= f.label :building_id %>
<%= f.text_field :building_id %>
<br>
<%= f.submit "Create building", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>
But i understand this only creates the new building, not the units associated with them.
You cannot have a form inside a form – you will have to use what’s called nested attributes.
I assume a building has many units, and a unit belongs to a building. Then your code needs to be as follows:
Building
Unit
Form
Note the
fields_forform helper (pretty self explanatory):Put the following inside your form:
When you reload the page, you will see that your form probably doesn’t contain any fields for units just yet. This is because the building instance inside the form does not have any units yet – do the following inside your controller to see unit fields:
Now you should see three sets of unit fields inside the form. If you fill them in and submit the form, they will be saved as children of that building – if you leave them blank, they won’t.
:reject_if => lambda { |a| a[:bedrooms].blank? }inside the building model takes care of that: If the bedrooms field is left blank, the unit will not be saved.This is all you need!
If this was a bit too fast, just watch this railscast.
Also, check out this awesome gem called nested_forms, which gives you links to add and remove nested form fields on the fly (allowing you to get rid of that cumbersome extra line in your controller).