Vidar
29 March 2009
Rails 2.3 nested attributes with Ajax
Rails 2.3 was recently released and with it came a nice feature called nested attributes or nested model mass assignment. It allows you to specify code like the following in your your view (taken from the release notes ):
-form_for @customer do |customer_form| = customer_form.label :name, 'Customer Name:' = customer_form.text_field :name - customer_form.fields_for :orders do |order_form| = order_form.label :number, 'Order Number:' = order_form.text_field :number // The allow_destroy option in the model enables deletion of child records = order_form.check_box :_delete = customer_form.submit
But what if you need to submit a form or some data using Ajax? Then you can’t use the rails helpers. As it turns out it’s pretty easy once you understand how the helpers generate the form data.
The above code indicates we have a Customer model with a one-to-many relationship to Order. If you run the code you will see that the first level generates input fields with a name attribute like this
customer[name]
just like we are used to from before using normal mass assignment. However on level 2 it looks like this
# When new, you only get the attribute customer[orders_attributes][0][name] # When an id exists, you also get a hidden field # to indicate which record we are working with customer[orders_attributes][0][id]
This can nest infinitely deep. Let’s say we also have a model LineItems with a one-to-many association to Order, you’ll get
customer[orders_attributes][0][line_items_attributes][0][some_field] customer[orders_attributes][0][line_items_attributes][1][some_field]
The [0] indicates that this is the first element in the list of many records ie customers.first.orders.first, so a [1] would indicate customers.first.orders.second and so on. This preserves the stored order of elements.
Lastly, it’s now possible to mark for deletion. Just do this
customer[orders_attributes][2][_delete]
to delete the third element in customer.orders.
So what’s so ingenious about this? My models in the project I’m working on are nested 5 levels deep. Using this technique this is my controller code
# in create @product = Product.create(params[:product]) # in update @product = Product.find(params[:id]) @product.update_attributes(params[:product])
3 lines of code to create and update 5 levels deep nested associations. I get validations for each model, atomic saves and get to remove 100 lines of code in models. Use these conventions to assemble parameters when you are using Ajax and it’ll just work. Beautiful. « Back to posts Write a new comment
I am using the same technique on my forms but I am unable to get the validations to work, could you please cover that or add a comment explaining how to use validations with this technique?
Thanks.
Hi Luis! Sorry for the late reply, hopefully you worked it out already. On this particular project I’m only using javascript validations because I’m 100% sure the user will have it enabled at all times. However, using the same technique on another project, I just added model validations in addition to the has_many belongs_to and the accepts_nested_attributes_for and validations just worked.
If you’re using ajax you might need to write a custom helper for displaying the errors, but the errors should be in your model. Confirm using the console.
Luis,
Is this still the best way to do it, or have there been other ways that are better now? You can also email me at mrmanishs@gmail.com
Manish
longitudinal pontine bundles http://wiki.answers.com/Q/User:Med-helper buy clomid basal metabolic rate information about clomid
immunoreactive insulin http://wiki.answers.com/Q/User:Med-helper – clomid
online te betalen op onze gokkasten. Online pokeren sites overzicht waar je online kunt pokeren, vindenIn deze fruitautomaten hal vind je een overzicht van alle automaten.
Alle online pokeren en de nieuwste pokeren gratis gokken of betaald via bijv ideal. gokkasten fruitkings.
Wilt u het laatste nieuws over nieuwe gokkasten en leuke acties in uw email?