#196 Nested Model Form (revised)
Handling multiple models in a single form is easy with accepts_nested_attributes_for. Here you will also learn how to add and remove nested records through JavaScript.
- Download:
- source code
- mp4
- m4v
- webm
- ogv
This was one of the first casts that got me into Railscasts so I'm glad to see an update.
Just a word of caution to new users of this technique: when you have a hammer everything can look like a nail. Dynamic nested forms like this are extremely powerful and can sometimes grant the user too many chances to input bad data.
If you find yourself needing complex validations to regulate the the data coming in from the form, a solution like this might not be what's in order and you might want to limit the scope of what is possible to do. Ryan's simple example here is spot on.
This dynamic nested form technique has worked wonders for me (Thanks, Ryan!) but I've been bitten by applying it to the wrong use cases-- use discretion when deciding on a UX.
I think you should have mentioned Cocoon
I'm using Cocoon... it seems pretty good so far.
Cocoon is cool
cocoon is cool
Hi
Can someone help me here. I am new with rails and trying to dynamically add fixed number of pre-populated nested forms using cocoon. Please be kind enough to read more details here.
http://stackoverflow.com/questions/15072932/dynamically-adding-fixed-number-of-prepopulated-nested-forms
Thanks a lot!!
thanks Ryan...
@anyone Does anyone have an example carrierwave intregration (file or image upload in in a nested model)
controller:
View:
Amazing how much simpler this is, especially since the power shown in the unrevised editions is one of the thing that made me think Ruby was so much better than the alternatives. Thanks, Ryan!
I actually feel good about spending the $9 per month for episodes like this! That's a big statement considering how cheap I am.
How do i get it to work with simple form?
Use Cocoon :) https://github.com/nathanvda/cocoon
Thank you Ryan. I like this nested model forms that starting from scratch. This is awesome.
+1
If you want more flexibility, try awesome_nested_fields. =)
+1 with awesome_nested_fields. It's got very detailed wiki
I just tried using you gem...it works great but I cant delete child objects even after setting allow_destroy: true....pls do you have any sugestions?
easy fix...got me disturbed for 30mins..I added :dependent => :destroy...maybe you want to add this to you documentation just to be prevent another person (newbie i suppose) from running around.
has_many :phones, :dependent => :destroy
accepts_nested_attributes_for :phones, allow_destroy: true
Thanks. Awesome gem!
Does anyone know how you would make the questions answerable (perhaps assuming that you were using Devise for user authentication and had access to current_user)? I'm guessing that you would have a model that stored the ID from a User model as well as an ID from the Answer model. So then on the show page, each answer that was listed would be a link that would allow the user to answer the question.
So i guess my question is: What code would you use to then save this into the database when the user clicked the link?
Also, is this the best way to go about this? should this actually use a form instead? It seems like an easy thing to do but I'm not sure of what the Rails way to approach it is. Thanks!
See: https://github.com/mark-d-holmberg/sed/tree/master/app/models
awesome, thanks!
Nice, thanks Mark. Does anyone else have any other examples?
What is the difference between Cocoon and awesome_nested_fields?
awesome_nested_fields is more flexible (you can put the code anywhere) and has an JS Callbacks and API.
Any reason not to use your nested_form gem anymore?
I was wondering this also?
Me too ?
These posts are over a year old, did anyone find out as to why to use the techniques in this episodes rather than the nest_form gem?
I'm getting in this episode the same strange thing some other user mentioned in another thread. It seems it's cut off in the end, interrupting Ryan mid-sentence... Probably just a few seconds of video cut off but I think it's worth mentioning.
Great episode as always.
Same thing happened to me when watching this and Episode #343.
What if you wanted to put a validation on Question to ensure that it's not blank... or maybe validate its uniqueness against all of the other Questions to ensure none of the names are the same?
The validations are easy, but the hard part is correlating those Rails errors to which Question input actually failed in the case of multiple children errors. If you had several questions that each were non-unique or perhaps blank, Rails will simply merge all of those errors into one key, and you have no way of associating those out independently from one another.
Does anyone know a workaround on this problem?
THANK YOU! I wrote my college Software Engineering project using the old version of this video, and this new approach makes it so much simpler! Keep them coming.
Awesome update on this technique, Ryan. And thanks everyone for the additional gem suggestions (cocoon and awesome_nested_fields).
How this would work when the models are associated via a has_many :through association?
I'm trying to follow the same steps, however nothing is displayed in my form.
I remember that the first episode regarding this topic used to build the objects in the controller, e.g. Question.new, so that they would be made available in the view. I found really weird that this wasn't mentioned this time.
Did that behavior changed in Rails?
In order to make it work with has_many :through I need to build "by hand" the associated object in my controller?
Thanks :)
I'm also having an issue with my model that contains a has_many :through association.
It would be nice to see this approached in the video... though that might be asking too much in your scope of the tutorial.
EDIT: I actually don't have a problem with my has_many :through... it works fine. I found that my coffescript had its indents wrong and was throwing an error. Once the coffeescript was fixed everything works like a charm.
thanks for your good work!
Haha, I'm still having a through association issue...see below — any pointers??
After this Railscast I found out that internally Rails is handling the build of the associated object when needed. It seems that this behavior has in fact changed.
The only thing I needed to add is a instantiation of my join model to the action 'new'.
I have a Proposal model which can have many Product through a join model called ProductEntry.
In the action 'new' from my ProposalsController I simply added:
This is just to display the form field when no ProductEntry is available yet, which is always the case when I'm creating a new Proposal.
When I go and edit a Proposal, Rails automatically instantiate all ProductEntry that are associated. If I edit any of those ProductEntry (such as the quantity attribute that I have), it simply works too.
Yeah, I also had issues getting the form fields to show up if I didn't put anything in the controller.
My user model had a profile model. The relationship was has_one and belongs_to.
I had to add the following to the users controller.
Users Controller
Hi Ryan,
Thanks for all the great RailsCasts - I'm learning a ton of stuff!
I'm using your adding/deleting field partials fairly extensively and ran into a couple of things others may find useful:
Your .gsub('\n','') removing newlines causes slight horizontal shifting of fields on inline forms. This was easily fixed by escaping rather than removing newlines using .gsub('\n','
').
jQuery won't recognize events from controls created this way. Apparently the solution is to use .on() (formerly .live and .delegate) though I have yet to try this.
Thanks again for all your great tutorials and keep up the good work.
Cheers,
Peter
I think the proper way to prepare the fields HTML is as follows:
and then define
escape_html_attribute
as follows:This prevents the
&
in

from being escaped.In Rails 3.0.3 I get "undefined method `klass'" from the application_helper.
This is the syntax I'm using:
Is my syntax correct? Does "klass" work with my rails version?
Thanks
Your problem might be the same issue as mine. The object.send(association) doesn't seem to work for has_one relationships.
Anyone else have this issue or a solution?
Thanks
Using Rails 3.2.3, I did have this error but it is fixed (see below for changes):
You can see I was using different variable names than the example, but hopefully the comparison between the two code snippets below will indicate what might be worth changing in your code.
ERROR
undefined method `klass' for nil:NilClass
BEFORE CHANGES
AFTER 2 CHANGES (no more errors)
I hope that is helpful to some folks.
Thanks for these truly awesome tutorials.
Thank you @LucasCioffi, changing the location of my link_to_add definitely fixed the undefined method error!
I just came across this issue. It is as you expected: object.send(association) does not work the same way for has_one as it does for has_many. To get around this, I changed the link_to_add_fields helper as follows:
Basically, I changed
f.object.send(association).klass
tof.object.class.reflect_on_association(association).klass
and, since I use users/_fields.html.erb instead of user_fields.html.erb, I also changed the render line. Hope this helps, if you're still having that problem. If not, hope this helps some other lost soul of the future.-Christian B.
Quick Q Ryan - the models I'm working with are connecting using has_many :through, and I'm getting issues with creating the sub-objects via the update method, here's the exception:
For context, Quizzes have many questions through a join table.
Anyway, decent chance I'll have this fixed before anyone has a chance to reply, but seemed like something enough people might be trying to do to warrant a comment.
Back to figuring it out.. :D
Figured it out, key was using the actual join relationship rather than the target of the join, then everything pretty much "just worked"
I won't lie though, this also helped (from a comment on the second part of the complex forms casts) : http://pastie.org/987614
I am having the same issue, and still not clear how you resolved it, can you paste your before and after code?
Thanks!
I am having the same issue! Could you elaborate further on how you solved it?
Great tutorial as always. I did run into a problem though when trying to implement it into my app. When I add an extra field it didn't show up in the params sent to the controller.
I found the problem was I had put the form into a table and it didn't work well with this. I simply removed the table and it all started to work.
This is working great for me except for one issue. I have SEVERAL nested models.
A workout has_many steps, a step has_many actions, an action has_many instructions. When I click to add a new step, I would like that step to be populated with on action fieldset, and that action fieldset, populated with one instruction fieldset. But it just renders the empty step fieldset, I have to click the "add action" and then the "add instruction" buttons for those to render. Does anyone know how to get all the nested fieldsets to render when I add a step?
Data Associations:
has_many steps
In case anyone is interested, I was able to achieve this behavior outside of the controller, by just "clicking" the add_field buttons with js
You can accomplish this on the server side by building the nested object in your view. Use the "build_(association name)" method, which is provided by Active Record.
Inside the
_action_fields.html.erb
partial:Now the
fields_for :action
block will execute and render theaction_fields
partial.Naturally you would want to use this in the sub-nested partials as well.
Hi Dan, would you please share how you did this? Thanks
I am having trouble using auto-complete with multiple fields. The first one works but the second instance does not. Been working on trying to figure out how to make it work for close to a week now. Any help would be great!
Please note I do NOT want to tokenize. Do in face want to set other fields along side the auto-complete text field too.
Thanks!
I'm trying to add an image field to my survey. I can get the image to upload and to show on the Show page. But when I go back to the Edit view, there is no image and I still see the "No file chosen" text next to the Choose File button.
I have this line of code in my Show view:
<%= image_tag question.image_url(:thumb).to_s if question.image? %>
but if I try to put that into the _form view then I get an unknown variable or method error.
I've tried a couple of if statements but haven't gotten it to work.
Thanks to anyone who can help.
@Charlie, were you able to get your issue to work, regarding "No File Chosen"? I'm trying to have that text hidden until a file is uploaded.
I got an error on jquery:
$("form").on is not a function
I upgrated jquery to 1.7.1, but it still error.
Thanks to anyone who can help.
Thanks for this brilliant tutorial! I am new to rails and this one made a few pennies drop.
How can I achieve that destroying a question automatically destroys all associated answers records in the database?
figured it out with
:dependent => :destroy
Hi, I followed the tutorial step by step
but my remove function won't work.
add function work fine, remove using checkbox works fine. Why?
Seems there's something wrong with the coffee indent. I'm new to this. What's wrong with it?
i'm trying to render a partial form in a show view but it doesn't render it, do you know why would this be?
I was able to get grandchildren to work in the forms with a special application helper function:
Essentially, you have to create the grandchildren in this helper to have an object for the fields_for to attach to.
I tried adding this method for adding grandchildren but I get the error:
undefined method 'klass' for nil:NilClass
passing in:image
as the child_association. Could you possible post your form code?I got this figured out and posted the answer here: http://stackoverflow.com/questions/16839555/rails-cast-196-197-nested-model-generation/16867048#16867048
How would you do this if your model is not ActiveRecord based? Since I'm not using ActiveRecord, I don't have access to the accepts_nested_attributes_for method.
Great Railcast. There seems to be a problem rendering the nested model fields when implementing this solution with models that have a one-to-one association. One-to-many associations show nested model fields fine, but not one-to-one.
Hi Jesus H. Did you ever figure this out? I'm having the exact same issue. Thanks!
I'm not sure if it's exactly the same thing, but what really saved me (for what I needed) was this https://github.com/moo-li/Simple-parent-child-forms-in-Rails-3.1
Great railcast anyways!
I'm getting a
Missing partial
in thelink_to_add_fields
method and can't for the life of me figure out why. I've followed the setup exactly as described in the RailsCast.It seems to be coming from this line:
Never mind, typo in the partial file name......
You know you can delete your comments if you find out your question isn't helpful to the others anymore, right?
I was hoping so, but all I can see is Reply. It appears you can only Delete within a certain timeframe.
This is a great piece of knowlege, thanks!
I encountered one problem.
The dynamic form doesn't work when I added
validates :question_id, presence: true
to the Answer model class.Form is not saving and returning error: Questions answers question can't be blank
This happens only in case when you try to add a new question and add a new answer to it.
Why is this happening?
I encountered this too!.. any solutions so far?
Just ran into this as well. Anyone found a decent workaround?
If you, like me, had trouble converting the Coffeescripts to pure Javascripts, this site is very helpful:
http://cs2js.nodejitsu.com/
I like this one even more.
Why is CoffeeScript so popular these days?
I figured out how jQuery works and now I have to start over and learn Coffeescript :-(
Anyone got this working with mongoid?
Never mind. Works fine with Mongoid.
Great tutorial, Ryan!
I was lucky enough to get this working on my machine.
The only problem I have is that the nested attributes are not saved to the database in the order in which I created them.
E.g. sometimes I create 3 answers at once, then click "Update" and the answers do appear on the form, but not in the correct order. I can't see any pattern in there, so I assume that they get saved to the database randomly.
Is there any way to fix this?
I created a migration to add a position:integer field, used a hidden_field inside partial with :class => 'position' and included this line of js before event.preventDefault() to the .add_fields event:
> $(this).prev().find('.position').val(time)
and on has_many association, i used
Thank you for this :)
Hi guys, nice episode.
Ryan, I think that the following code could help handling validation errors.
What do you think?
Thanks,
Mauro
Sweet.. I was looking for this... Thanks!
Base on this example, How do we delete an entire survey together with it's questions and answers? Please help...
Well, you could add
:dependent => :destroy
to eachhas_many
association. and then simply delete your Survey!I would like to add a 'Copy' button that creates a new copy of the question with the same set of answers. I think it will be similar to the link_to_add_fields, but I cannot figure out how to capture user input and create a new nested object with those values on the fly. Any help will be appreciated. Thanks.
Did you find help for this? I, too, would like to copy the record above to create a new record - like an Excel sheet...
in our scenario we need to vary the number of associated records allowed. We have validation in the model i.e
accepts_nested_attributes_for :answers , :limit => 4,:allow_destroy => true
My question is . how do we prevent the Add Answers link from being rendered if we already have reached our limit ?
I'm having some trouble adapting railscasts with nested parameters using strong_parameters. I think this form creates an empty hash in answers_attributes and questions_attributes which cause problems on update for strong_parameters.
In order for this to work with Rails 4.0 or later, you have to use http://blog.trackets.com/2013/08/17/strong-parameters