Skip to content

Commit

Permalink
Refactor region_options_for_select to take a collection of regions in…
Browse files Browse the repository at this point in the history
…stead of a parent_ragion_code.
  • Loading branch information
jim committed May 21, 2012
1 parent ae1333b commit ada9fc2
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 19 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
@@ -1,9 +1,11 @@
### HEAD

### 1.0.0.beta 3

Bug Fixes

* Removed some 1.9 syntax taht prevented the gem from running on Ruby 1.8
*

Enhancements

* Region select options are now sorted (lukast-akra)
Expand All @@ -12,3 +14,6 @@ API Changes

* region_options_for_select now takes priority region codes in an options hash
under the key 'priority'.
* The API for region_options_for_select now expects a collection of Carmen::Regions
as its second argument instead of a parent region. This makes it simple to provide
a custom collection of regions to build a select from.
29 changes: 25 additions & 4 deletions README.md
Expand Up @@ -9,7 +9,7 @@ carmen-rails is a Rails 3 plugin that supplies two new form helper methods:
Just add carmen-rails to your Gemfile:

```ruby
gem 'carmen-rails', '1.0.0.pre'
gem 'carmen-rails', '1.0.0.beta3'
```

## Usage
Expand All @@ -18,14 +18,35 @@ gem 'carmen-rails', '1.0.0.pre'
<%= form_for(@order) do |f| %>
<div class="field">
<%= f.label :country_code %><br />
<%= f.country_select :country_code, priority: %w(US CA), prompt: 'Please select a country' %>
<%= f.country_select :country_code, {priority: %w(US CA)}, prompt: 'Please select a country' %>
</div>
<% end %>
```

More docs coming soon.
## How do I only display a subset of countries/regions?

Carmen had a concept of excluded countries in the old days, where you could
specify certain countries or regions to not include in a select.

The new (and much more flexible) way to handle this is to write a helper method
that returns the subset of regions you want to provide:

``` ruby
def only_us_and_canada
Carmen::Country.all.select{|c| %w{US CA}.include?(c.code)}
end
```

And then in your form something like this:

``` erb
<%= f.select :country, region_options_for_select(only_us_and_canada) %>
```

More docs coming soon. In the meantime, all of the public methods in
carmen-rails [have been thoroughly TomDoc'ed](https://github.com/jim/carmen-rails/blob/master/lib/carmen/rails/action_view/form_helper.rb).

### Demo app

There is a [live demo app](http://carmen-rails-demo.herokuapp.com) that shows
carmen-rails in action.
carmen-rails in action, and includes a [step-by-step setup guide](https://github.com/jim/carmen-demo-app#readme).
106 changes: 92 additions & 14 deletions lib/carmen/rails/action_view/form_helper.rb
Expand Up @@ -2,40 +2,80 @@ module ActionView
module Helpers
module FormOptionsHelper

# Return select and subregion option tags for the given object and method.
# Generate select and subregion option tags for the given object and method. A
# common use of this would be to allow users to select a state subregion within
# a given country.
#
# object - The model object to generate the select for
# method - The attribute on the object
# parent_region_or_code - An instance of Carmen::Region or a 2-character
# country code.
# options - Other options pertaining to option tag generation. See
# `region_options_for_select`.
# html_options - Options to use when generating the select tag- class,
# id, etc.
#
# Uses region_options_or_select to generate the list of option tags.
#
# Example:
#
# subregion_select(@object, :region, {priority: ['US', 'CA']}, class: 'region')
#
# Returns an `html_safe` string containing the HTML for a select element.
def subregion_select(object, method, parent_region_or_code, options={}, html_options={})
parent_region = determine_parent(parent_region_or_code)
tag = InstanceTag.new(object, method, self, options.delete(:object))
tag.to_region_select_tag(parent_region, options, html_options)
end

# Return select and country option tags for the given object and method.
# Generate select and country option tags for the given object and method. A
# common use of this would be to allow users to select a state subregion within
# a given country.
#
# object - The model object to generate the select for
# method - The attribute on the object
# options - Other options pertaining to option tag generation. See
# `region_options_for_select`.
# html_options - Options to use when generating the select tag- class,
# id, etc.
#
# Uses region_options_or_select to generate the list of option tags.
#
# Example:
#
# country_select(@object, :region, {priority: ['US', 'CA']}, class: 'region')
#
# Returns an `html_safe` string containing the HTML for a select element.
def country_select(object, method, options={}, html_options={})
tag = InstanceTag.new(object, method, self, options.delete(:object))
tag.to_region_select_tag(Carmen::World.instance, options, html_options)
end

# Generate option tags for the subregions of a region.
# Generate option tags for a collection of regions.
#
# regions - An array or Carmen::RegionCollection containing Carmen::Regions
# selected - the code of the region that should be selected
# options - The hash of options used to customize the output (default: {}):
#
# To use priority regions (which are included in a special section at the
# top of the list), provide an array of region codes at the :priority
# option:
#
# region_options_for_select(@region, 'US', priority: ['US', 'CA'])
# region_options_for_select(@region.subregions, 'US', priority: ['US', 'CA'])
#
# Returns an `html_safe` string containing option tags.
def region_options_for_select(parent_region, selected=nil, options={})
def region_options_for_select(regions, selected=nil, options={})
options.stringify_keys!
priority_region_codes = options['priority'] || []
region_options = ""

unless priority_region_codes.empty?
unless regions.respond_to?(:coded)
regions = Carmen::RegionCollection.new(regions)
end

priority_regions = priority_region_codes.map do |code|
region = parent_region.subregions.coded(code)
region = regions.coded(code)
[region.name, region.code] if region
end.compact
unless priority_regions.empty?
Expand All @@ -44,29 +84,57 @@ def region_options_for_select(parent_region, selected=nil, options={})
end
end

main_options = parent_region.subregions.map { |r| [r.name, r.code] }
main_options = regions.map { |r| [r.name, r.code] }
main_options.sort!{|a, b| a.first.unpack('U').to_s <=> b.first.unpack('U').to_s}
region_options += options_for_select(main_options, selected)
region_options.html_safe
end

# Return select tag with the name provided containing country option
# tags.
# Generate select and country option tags with the provided name. A
# common use of this would be to allow users to select a country name
# inside a web form.
#
# name - The name attribute for the select element.
# options - Other options pertaining to option tag generation. See
# `region_options_for_select`.
# html_options - Options to use when generating the select tag- class,
# id, etc.
#
# Uses region_options_or_select to generate the list of option tags.
#
# Example:
#
# country_select_tag('country_code', {priority: ['US', 'CA']}, class: 'region')
#
# Returns an `html_safe` string containing the HTML for a select element.
def country_select_tag(name, value, options={})
subregion_select_tag(name, value, Carmen::World.instance, options)
end

# Generate select and subregion option tags for the given object and method. A
# common use of this would be to allow users to select a state subregion within
# a given country.
#
# Return select tag with the name provided containing subregion option
# tags.
# name - The name attribute for the select element.
# parent_region_or_code - An instance of Carmen::Region or a 2-character
# country code.
# options - Other options pertaining to option tag generation. See
# `region_options_for_select`.
# html_options - Options to use when generating the select tag- class,
# id, etc.
#
# Uses region_options_or_select to generate the list of option tags.
def subregion_select_tag(name, value, parent_region_or_code, options = {})
#
# Example:
#
# subregion_select_tag('state_code', 'US', {priority: ['US', 'CA']}, class: 'region')
#
# Returns an `html_safe` string containing the HTML for a select element.
def subregion_select_tag(name, value, parent_region_or_code, options = {}, html_options = {})
options.stringify_keys!
parent_region = determine_parent(parent_region_or_code)
priority_regions = options.delete(:priority) || []
opts = region_options_for_select(parent_region, value, :priority => priority_regions)
opts = region_options_for_select(parent_region.subregions, value, :priority => priority_regions)
html_options = {"name" => name,
"id" => sanitize_to_id(name)}.update(options.stringify_keys)
content_tag(:select, opts, html_options)
Expand Down Expand Up @@ -94,17 +162,27 @@ def to_region_select_tag(parent_region, options, html_options)
add_default_name_and_id(html_options)
priority_regions = options[:priority] || []
value = value(object)
opts = add_options(region_options_for_select(parent_region, value, :priority => priority_regions), options, value)
opts = add_options(region_options_for_select(parent_region.subregions, value, :priority => priority_regions), options, value)
content_tag("select", opts, html_options)
end
end

class FormBuilder
# Generate select and country option tags with the provided name. A
# common use of this would be to allow users to select a country name inside a
# web form.
#
# See `FormOptionsHelper::country_select` for more information.
def country_select(method, options = {}, html_options = {})
@template.country_select(@object_name, method,
options.merge(:object => @object), html_options)
end

# Generate select and subregion option tags with the provided name. A
# common use of this would be to allow users to select a state subregion within
# a given country.
#
# See `FormOptionsHelper::subregion_select` for more information.
def subregion_select(method, parent_region_or_code, options={}, html_options={})
@template.subregion_select(@object_name, method, parent_region_or_code,
options.merge(:object => @object), html_options)
Expand Down
25 changes: 25 additions & 0 deletions spec/carmen/action_view/helpers/form_helper_spec.rb
Expand Up @@ -125,6 +125,31 @@ def test_basic_subregion_select
assert_equal_markup(expected, html)
end

def test_region_options_for_select
regions = Carmen::Country.all
expected = <<-HTML
<option value="ES">Eastasia</option>
<option value="EU">Eurasia</option>
<option value="OC" selected="selected">Oceania</option>
HTML
html = region_options_for_select(regions, 'OC')

assert_equal_markup(expected, html)
end

def test_region_options_for_select_with_array_of_regions_and_priority
regions = [Carmen::Country.coded('ES'), Carmen::Country.coded('EU')]
expected = <<-HTML
<option value="ES">Eastasia</option>
<option disabled>-------------</option>
<option value="ES">Eastasia</option>
<option value="EU">Eurasia</option>
HTML
html = region_options_for_select(regions, nil, :priority => ['ES'])

assert_equal_markup(expected, html)
end

def method_missing(method, *args)
fail "method_missing #{method}"
end
Expand Down

0 comments on commit ada9fc2

Please sign in to comment.