Skip to main content

Nested Form In Rails 3

What is "Nested form In Rails 3" and when do we use it?

This is a Rails gem for conveniently manage multiple nested models in a single form. It does so in an unobtrusive way through jQuery or Prototype.

Example :-

Suppose we have two models "Profile" and "Picture". We want to get all the information in the same form. In this case we got to use "Nested Form".

What are the steps to setup nested form gem in your app?


Add it to your Gemfile (by writing gem "nested_form" to you Gemfile) then run bundle to install it .

Asset Pipeline Setup

And then add it to the Asset Pipeline in the application.js file:

//= require jquery_nested_form

and don't forget to do $ bundle install

Non Asset Pipeline Setup

If you do not use the asset pipeline, run this generator to create the JavaScript file.

rails g nested_form:install
You can then include the generated JavaScript in your layout.

<%= javascript_include_tag :defaults, "nested_form" %>


How do we use this in our project?

Model Setup

class Profile < ActiveRecord::Base

    has_many :pictures, :as => :imageable

    accepts_nested_attributes_for :pictures, :allow_destroy => true, :reject_if => Proc.new { |c| c['image'].blank? }

Here we have Profile model which has many pictures. We want to accept attributes of Picture model in Profile model and we want to allow nested attributes to be destroyed (so :allow_destroy => true). We don't want entry in DB if no image is selected in the form(so :reject_if => Proc.new { |p| p['image'].blank? })

View Setup

<%= nested_form_for @profile, :url => admin_profile_path(@profile), :method => :post, :multipart => true, :html => { :class => "new-profile" } do |form|-%>

    <%= form.text_field :name, :placeholder=>"Profile Name" %>

    <%= form.fields_for :pictures, @product.pictures.new do |picture| %>

        <%= picture.file_field :image %>

        <%= picture.link_to_remove raw("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"), :class => "red button", :alt => "Remove" %>

    <% end -%>

<%= form.link_to_add "Add New Picture", :pictures, :class => 'small blue button' %>

<%= form.submit 'Update', :class => 'button green' %>

Here we have a simple view to understand nested form view. 

We have got a form object for profile. We want to take a name for profile so we have a form.text_field.
Now in the same form we want to take pictures related to this profile so we have use form.fields_for :pictures . This fields for help will generate fields for picture which user wants to upload for this profile.

Nested forms provides two very useful and nice helpers.

1. picture.link_to_remove :- This helper provides a link which will remove that particular row of picture fields in which it is present. This must be inside picture object scope (which is obvious :P ).

2. form.link_to_add :- This helper provides a link which will add new fields for picture. This must be outside of picture and inside of form object.

Using Partial

It is often desirable to move the nested fields into a partial to keep things organized. If you don't supply a block to fields_for it will look for a partial and use that.

<%= form.fields_for :pictures %>

In this case it will look for a partial called "picture_fields" and pass the form builder as an form variable to it.


JavaScript events

So here comes JS. This is very much useful when you are using nested form and you would need this for sure if you want to make you form smart and cool.

Now after adding/removing picture fields you want to some JS things so need call backs. After adding or removing the field a set of custom events is triggered on this field. Using form example from above, if you click on the "Add a picture" link, nested:fieldAdded and nested:fieldAdded:tasks will be triggered, while nested:fieldRemoved and nested:fieldRemoved:tasks will be triggered if you click "Remove this picture" then.

$(document).on('nested:fieldAdded', function(event){

    // this field was just inserted into your form

    var field = event.field; 

    // it's a jQuery object already! Now you can find date input

    var dateField = field.find('.date');

    // and activate datepicker on it

    dateField.datepicker();

});



And here you go. This was a simple explanation about nested form (specially for beginners). I have shared my view on how to use nested form. Your comments are most welcome.

Spacial thanks to Nested form documentation on GitHub.


Comments

Popular posts from this blog

3 Dimensions to Scaling: The scaling cube

Source: https://thenewstack.io/from-monolith-to-microservices/  X-axis scaling Running multiple copies of an application behind a load balancer. Each copy can handle 1/N of the load. Where N is the number of running copies. This is simple and commonly used approach to scale. Cons * Each copy accesses all the data, cache size will be higher. * Doesn't solve increasing development and application complexity. Y-axis scaling Splitting the application into multiple, different services. Then more infra resources can be added to only the micro-service which is bottleneck in the architecture. Here cached can be utilized efficiently, only where it is needed. Z-axis scaling Each server runs same copy similar to X-axis scaling. The big difference is that each server. Some component of the system is responsible for routing each request to the appropriate server. This is commonly used to scale databases where data is partitioned(a.k.a sharded) Pros * Each server

Reactive Microservices with Vert.x(Vertx.io)

Vert.x is an event driven and non blocking “Platform” where we can develop our application on. Vert.x is like Node.JS, but the biggest difference is that it runs on the JVM, it’s scalable, concurrent, non-blocking, distributed and polyglot. Following four key properties of Vert.x helps us in developing reactive applications. Async and non-blocking model Elastic Resilient Responsive Async and non-blocking model None of the Vert.x APIs block the calling thread(with few exceptions). If the result can be found quickly, It will be returned; Otherwise it will be handled by a handler to receive event sometime later. vertx      .createHttpServer()      .requestHandler(r -> {            r.response()            .end("<h1>Hello from my first " + "Vert.x 3 application</h1>"); })            .listen(8080, result -> {                 if (result.succeeded()) {                      fut.complete();                 } else {      

Validating Nested Models

What is validation ? Validations are required for ensuring that the received data is correct and valid. If the received data is valid then we do the further processing with the data. Nested Model Validation Nested model is sometimes tricky when you have complex associations. Here I'm explaining how we can do nested model validation. We use nested form to save associations through its parent model. Generally we do: class Album < ActiveRecord::Base   has_many :songs   accepts_nested_attributes_for :songs end When we are using nested form we want to save a new or edit an existing album with songs. Now suppose we want all the songs to be removed on removal of the album. class Album < ActiveRecord::Base   has_many :songs   accepts_nested_attributes_for :songs, :allow_destroy => true end At this point we can detect and reject empty association entries class Album < ActiveRecord::Base   has_many :songs   accepts_n