This app is a proof of concept to illustrate how to use carmen-rails inside a simple form in a Rails app.
carmen-rails depends upon carmen for its geographic data. If you want to customize the data generated by these helpers, the Carmen docs explain how.
Throughout this example, it is assumed that the code is operating on an Order
model. Be sure to change all references to order
to whatever is appropriate
for your application.
Add carmen
and carmen-rails
to your Gemfile, using these versions:
gem 'carmen', github: 'seangaffney/carmen'
gem 'carmen-rails', '~> 1.0.0', github: 'jim/carmen-rails'
carmen-rails provides form helpers for country or subregion selects:
# For the standard rails form helpers:
<div class="field">
<%= f.label :country_code %><br />
<%= f.country_select :country_code, priority: %w(US CA), prompt: 'Please select a country' %>
</div>
<div class="field">
<%= f.label :state_code %><br />
<%= render partial: 'subregion_select', locals: {parent_region: f.object.country_code} %>
</div>
# Or alternatively, with simple_form:
<%= simple_form_for @order do |f| %>
<%= f.input :country_code do %>
<%= f.country_select :country_code, prompt: 'Please select a country' %>
<% end %>
<%= f.input :subregion_code do %>
<%= render 'subregion_select', parent_region: f.object.country_code %>
<% end %>
<% end %>
Here is the content of the subregion_select
partial:
<div id="order_state_code_wrapper">
<% parent_region ||= params[:parent_region] %>
<% country = Carmen::Country.coded(parent_region) unless parent_region.nil? %>
<% if country.nil? %>
<em>Please select a country above</em>
<% elsif country.subregions? %>
<%= subregion_select(:order, :state_code, parent_region) %>
<% else %>
<%= text_field(:order, :state_code) %>
<% end %>
</div>
Note that we're defaulting to a text field input when we don't have subregion information for a country, and that if we don't have a country at all, we show a simple message.
Now we will add a small script in app/assets/javascripts/orders.js.coffee
that replaces the subregion select when the country
select's value changes. A wrapper div has been added to make this simpler.
$ ->
$('select#order_country_code').change (event) ->
select_wrapper = $('#order_state_code_wrapper')
$('select', select_wrapper).attr('disabled', true)
country_code = $(this).val()
url = "/orders/subregion_options?parent_region=#{country_code}"
select_wrapper.load(url)
Now we just need to add a route to config/routes.rb
as follows:
resources :orders do
collection do
get :subregion_options
end
end
Or alternatively:
# Must be ABOVE resources: orders
get '/orders/subregion_options' => 'orders#subregion_options'
And a basic controller action to the appropriate controller:
def subregion_options
render partial: 'subregion_select'
end
I'll demonstrate adding cities by adding city data for Mainland China. But the principle is the same no matter which countries' cities you choose to include.
The structural data goes in the lib/carmen
directory.
The locale files containing various languages' translations go into the config/locales/carmen
directory.
Then we tell Carmen about the new structural data and translations that we've added:
# In config/initializers/carmen.rb
# Tells Carmen about the extra structural data for cities that we added
Carmen.append_data_path File.expand_path('../../../lib/carmen/', __FILE__)
# In config/application.rb
# Tells Carmen about the extra translations for cities that we added (loads not only config/locales but all subdirectories as well)
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
See the source code of the views for the example