DynamicSelectable is a Rails gem that allows you to easily create collection_select
fields with results that dynamically populate a related field. The dynamic population occurs with the help of the jQuery library jquery-dynamic-selectable written by Andrey Koleshko.
How about a use case? Let's say your application allowed users to look up parts for their vehicle. A user selecting their car's model might include the following:
- User selects the
Make
of their vehicle - The
Model
field is populated with models of the selectedMake
- User selects the
Model
of their vehicle
DynamicSelectable makes the above easy to do by providing a generator for your dynamic collection_select
along with a new FormHelper
method called dynamic_collection_select
.
To see this gem in action, you can check out the sample application here.
Warning: If you are updating from 0.0.2
you will need to re-generate any content created with rails generate dynamic_selectable:select
.
Add the following line to your application's Gemfile:
gem 'dynamic_selectable', git: 'https://github.com/atni/dynamic_selectable.git'
Install the gem by running bundle install
.
Run the gem's install generator:
$ rails generate dynamic_selectable:install
If you are using Devise for user authentication, you will want to add a before_filter to skip authentication in the newly generated app/controllers/select/select_controller.rb
:
class DynamicSelectable::SelectController < ApplicationController
# skip_before_filter :authenticate_user!
end
Finally, you'll want to add the following require to your application.js
:
//= require jquery-dynamic-selectable
Now that you have DynamicSelectable installed, you're ready to start creating some dynamic_collection_select
fields in your application!
The first step to creating a dynamic_collection_select
is to generate a controller and route for it. Using the vehicle example from above, your Make
and Model
models might look like the following:
# == Schema Information
#
# Table name: makes
#
# id :integer not null, primary key
# name :string
# created_at :datetime not null
# updated_at :datetime not null
#
class Make < ActiveRecord::Base
end
# == Schema Information
#
# Table name: models
#
# id :integer not null, primary key
# name :string
# make_id :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class Model < ActiveRecord::Base
belongs_to :make
end
To generate the controller and route necessary for your selection of Make
to dynamically populate your selection of Model
, run the following:
# Usage: rails generate dynamic_selectable:select parent child value_method text_method [sort_col:asc/desc]
$ rails generate dynamic_selectable:select make model id name name:asc
Now you just need to build your form. The method dynamic_collection_select
is very similar to collection_select, but contains the new dynamic_model
parameter. This parameter is a symbol representing the child model whose collection will be populated based on the value selected in this parent field.
If you would like to submit the value of the dynamic_collection_select
with the form, just add { submit_with_form: true }
to the options
hash.
def dynamic_collection_select(object, method, dynamic_model, collection, value_method, text_method,
options = {}, html_options = {})
A very simple form would look something like this:
<%= form_for(@vehicle) do |f| %>
<div>
<%= label_tag :make_id %>
<%= dynamic_collection_select :vehicle, :make, :model, Make.all, :id, :name,
{ include_blank: true }, {} %>
</div>
<div>
<%= f.label :model_id %>
<%= f.collection_select :model_id, [], :id, :name, {}, {} %>
</div>
<%# ... %>
<% end %>
That's it. Happy selecting!
By default, DynamicSelectable uses the object
and method
parameters of dynamic_collection_select
to generate data attributes used by the gem's Javascript. However, if you are creating a form for a gem like Ransack, the values you provide for these parameters could prevent DynamicSelectable from generating the necessary data attributes properly. To resolve this, you will need to manually specify these attributes in a data
hash within your tag's html_options
hash. For example:
<%= dynamic_collection_select :q, :make_id_eq, :model, Make.all, :id, :name,
{}, { data: { dynamic_selectable_url: '/dynamic_selectable/makes/:make_id/models',
dynamic_selectable_target: '#q_model_id_eq' } } %>
The value for dynamic_selectable_url
can be found in your routes:
$ rake routes | grep dynamic
dynamic_selectable_make_models GET /dynamic_selectable/makes/:make_id/models(.:format) dynamic_selectable/make_models#index
and the value for dynamic_selectable_target
is generated with your form. This can be found by inspecting the child element in your web browser.
$ rm app/controllers/dynamic_selectable/models_controller.rb
and remove the related line from your routes.rb
:
get ':make_id/models', to: 'models#index', as: :models
$ rm -rf app/controllers/dynamic_selectable
and remove the following block from your routes.rb
:
namespace :dynamic_selectable do
# ...
end
- Fork it ( https://github.com/atni/dynamic_selectable/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request