I recently had to implement a view with the classic search form with two select dependent on each other.  My aim was to leave the page as clean as possible and make the code that loads the options for the daughter dropdown reusable.
Suppose, therefore, to have two models, SpecializationType and Specialization, defined as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 
  | 
class SpecializationType < ActiveRecord::Base 
  # FIELDS 
  # RELATIONS 
  has_many :specializations 
  # TRIGGERS 
  # VALIDATIONS 
  validates :name, :presence => true 
  validates :description, :presence => true 
  # SCOPES 
  # OTHER 
  def to_s 
    name 
  end 
end 
 
 
class Specialization < ActiveRecord::Base 
  # FIELDS 
  # RELATIONS 
  belongs_to :specialization_type 
  has_and_belongs_to_many :users 
  # TRIGGERS 
  # VALIDATIONS 
  validates :name, :presence => true 
  validates :description, :presence => true 
  validates :specialization_type, :presence => true 
  # SCOPES 
  # OTHER 
  def to_s 
    name 
  end 
end  | 
In our template, we will create two dropdowns in this way:
1 2 3 4 5 6 7 8 9 10 11 
  | 
<%= form_tag users_path, {:method => :get, :class => "users_search_form"} do %> 
      <%= select_tag :specialization_type_id, options_from_collection_for_select(SpecializationType.all, "id", "name"), :prompt => "Select a specialization type" %> 
      <%= select_tag :specialization_id, options_from_collection_for_select([], "id", "name"), 
                     "data-option-dependent" => true, 
                     "data-option-observed" => "specialization_type_id", 
                     "data-option-url" => "/specialization_types/:specialization_type_id:/specializations.json", 
                     "data-option-key-method" => :id, 
                     "data-option-value-method" => :name %> 
      <br/> 
      <%= submit_tag "Cerca" %> 
  <% end %>  | 
How we can see, the doughter dropdown indicates many “date-option” attributes that provide everything it needs to load elements at runtime.
In particular:
“data-option-dependent” => true, indicates that this depends on a dropdown dropdown father
“data-option-observed” => “specialization_type_id”, specifies the id of the dropdown to be monitored. If its value changes, we’ll trigger the request to the server
“data-option-url” => “/specialization_type/:specialization_type_id:/specializations.json” is the url that we are going to call on the server. The script will replace :specialization_type_id: the id of the selected item in the dropdown father.
“data-option-key-method” => :id, indicates that we’ll use the ID field of the json returned by the server as attribute “key” for < option >
“data-option-value-method” => :name, indicates that we’ll use the NAME field in the json returned by the server as attribute “value” of < option >
Let’s add this jQuery script in the application.js file, in order to handle all dependent dropdown of our code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 
  | 
    jQuery(document).ready(function () { 
        $('select[data-option-dependent=true]').each(function (i) { 
            var observer_dom_id = $(this).attr('id'); 
            var observed_dom_id = $(this).data('option-observed'); 
            var url_mask = $(this).data('option-url'); 
            var key_method = $(this).data('option-key-method'); 
            var value_method = $(this).data('option-value-method'); 
            var prompt = $(this).has('option[value=]').size() ? $(this).find('option[value=]') : $('<option value=\"\">').text('Select a specialization'); 
            var regexp = /:[0-9a-zA-Z_]+:/g; 
            var observer = $('select#' + observer_dom_id); 
            var observed = $('#' + observed_dom_id); 
 
            if (!observer.val() && observed.size() > 1) { 
                observer.attr('disabled', true); 
            } 
            observed.on('change', function () { 
                observer.empty().append(prompt); 
                if (observed.val()) { 
                    url = url_mask.replace(regexp, observed.val()); 
                    $.getJSON(url, function (data) { 
                        $.each(data, function (i, object) { 
                            observer.append($('<option>').attr('value', object[key_method]).text(object[value_method])); 
                            observer.attr('disabled', false); 
                        }); 
                    }); 
                } 
            }); 
        }); 
    });  | 
Now we need to configure the following route in routes.rb file:
1 
  | 
get "specialization_types/:specialization_type_id/specializations" => "application#specializations", :as => "specializations", :format => :json  | 
And finally, implement the method in the controller:
1 2 3 4 5 6 
  | 
def specializations 
  specialization_type = SpecializationType.find(params[:specialization_type_id]) 
  respond_to do |format| 
    format.json { render :json => specialization_type.specializations } 
  end 
end  |