This is a simple contact manager application. What this application primarily demonstrates is the ability to add and remove multiple associated sub-models dynamically on a single form. The idea of a contact manager is well understood by most audiences and are thus commonly used as a demonstration application. This particular contact manager demonstrates (and improves upon) Ryan Bates “Handle Multiple Models in One Form” recipe (#13) from the Advanced Rails Recipes book.
In Ryan's original recipe, he added discrete field values (individual tasks on a to-do list) to the form. Any tasks that did not have an identifier associated with it was a new task, and any missing task identifiers from those currently in the database were assumed to be deleted.
project[new_tasks_attributes][name] = "a new task" project[existing_task_attributes][name] = "task 1" project[existing_task_attributes][name] = "task 3"
The controller would know to a the new task, and possibly remove task 2 if one currently exists in the database.
In the original recipe, the new and existing tasks were separated out using different identifiers in the form element names (new_task_attributes vs. existing_task_attributes“), however, to allow Rails to both construct and consume these values more naturally as nested models, we'd like to name them as Rails would expect and make them all tasks.
project[tasks][name] = "a new task" project[tasks][name] = "task 1" project[tasks][name] = "task 3"
The shortcoming to this recipe is when you need to send in a whole group of fields that need to be combined for a single record.
project[tasks][name] = "first new task" project[tasks][priority] = "urgent" project[tasks][name] = "another new task" project[tasks][name] = "task 1" project[tasks][priority] = "high" project[tasks][name] = "task 3" project[tasks][priority] = "low"
How does Rails know to construct the tasks with no unifying identifier? The name and priority values may not stay together in pairs when the request is processed, and further if you have optional fields such as the priority in this case, which task should get the priority?
This sample also utilizes the information from “Combine contact attributes in model”
git clone firstname.lastname@example.org:pothoven/contacts.git cd contacts bundle install rake db:migrate rake db:populate_states_provinces_countries rake assets:precompile rails server
bundle install rake db:migrate rake db:populate_states_provinces_countries rails server
Run on Heroku
gem install heroku heroku create git push heroku master heroku rake db:migrate heroku rake db:populate_states_provinces_countries heroku open
git pull git push heroku master