cocoon is a Rails3 gem to allow easier handling of nested forms. Nested forms are forms that handle nested models and attributes dynamically in one form. Some standard examples: a project with its tasks, an invoice with its ordered items. It is formbuilder-agnostic, so it works with standard Rails, or formtastic or simple_form.
This gem uses jQuery, it is most useful to use this gem in a rails3 project where you are already using jQuery. Furthermore i would advice you to use either formtastic or simple_form. I have a sample project where I demonstrate the use of cocoon with formtastic.
Inside your Gemfile
add the following: [ruby] gem "cocoon" [/ruby] Run the installation task: [ruby] rails g cocoon:install [/ruby] This will install the needed javascript file. Inside your application.html.haml
you will need to add below the default javascripts: [ruby] = javascript_include_tag :cocoon [/ruby] or using erb, you write [ruby] <%= javascript_include_tag :cocoon %> [/ruby] That is all you need to do to start using it!
Suppose you have a model Project
: [ruby] rails g scaffold Project name:string description:string [/ruby] and a project has many tasks
: [ruby] rails g model Task description:string done:boolean project_id:integer [/ruby] Edit the models to code the relation: [ruby] class Project < ActiveRecord::Base has_many :tasks accepts_nested_attributes_for :tasks end class Task < ActiveRecord::Base belongs_to :project end [/ruby] What we want to achieve is to get a form where we can add and remove the tasks dynamically. What we need for this, is that the fields for a new/existing task
are defined in a partial view called _task_fields.html
. Note: the name of the partial is really important, as this plugin will look for the partial named as the singular of the relation + _fields
. We will show the sample usage with the different possible form-builders.
Inside our projects/_form partial we then write: [ruby] - f.inputs do = f.input :name = f.input :description %h3 Tasks #tasks = f.semantic_fields_for :tasks do |task| = render 'task_fields', :f => task .links = link_to_add_association 'add task', f, :tasks -f.buttons do = f.submit 'Save' [/ruby] and inside the _task_fields
partial we write: [ruby] .nested-fields = f.inputs do = f.input :description = f.input :done, :as => :boolean = link_to_remove_association "remove task", f [/ruby] That is all there is to it! There is an example project on github implementing it called cocoon-formtastic-demo.
This is almost identical to formtastic, instead of writing semantic_fields_for
you write simple_fields_for
. There is an example project on github implementing it called cocoon_simple_form_demo.
I will provide a full example (and a sample project) later.
I define two helper functions:
This function will add a link to your markup that will, when clicked, dynamically add a new partial form for the given association. This should be placed below the semantic_fields_for
. It takes three parameters:
This function will add a link to your markup that will, when clicked, dynamically remove the surrounding partial form. This should be placed inside the partial _#{association-object-singular}_fields
.
!!!Important The partial should be named _#{association-object_singular}_fields
, and should start with a div of class nested-fields
. There is no limit to the amount of nesting, though.
I hope it can be of use. Let me know what you think.
Comments
Excelent work!! very useful gem. Thanks for share!!
Hello Nathan, I have opened up an issue for two level's nested form not working with my code. Can you please give me a hand with it? Thanks. Bharat
Great work on this gem - we've really been enjoying it so far. Could I ask how I might go about displaying one of the embedded forms by default, rather than having to actually click to add one? Also, how about requiring that at least one record be submitted to the embedded model, any idea on the general direction I'd need to take would be great!
You could do something like in your <code>new</code> action: <pre> @project = Project.new @project.tasks.build </pre> just taking the standard example of projects and tasks. And to make sure you need at least one record, you will need to write a validation in the parent model. Hope this helps.
Thanks for the response, it was helpful. I am revisiting this functionality in a new project and am trying to figure out how to add more than one field by default. Been doing some digging and trial/error but without luck. Any idea on a starting point for more than one nested field by default? I actually ran into this same issue in the last project, but ended up working around it. Thanks again!
Scratch that, there's a demonstration of how to do this in http://railscasts.com/episodes/196-nested-model-form-part-1?autoplay=true
Maybe you should out my follow-up article on nested-forms: http://www.dixis.com/?p=561 If you have more questions, shoot. Hope this helps.
Any updates on the example for using standard rails forms? I've tried to look for something but with no luck. Cheers!
Add comment