Commit 836073633b962466d83855f0fa25782e2bde3638

Authored by Isaac Canan
Committed by Rafael Martins
1 parent 4e00577f

[geolocalization]

Change Google API version to V3 and implements city and state validations for Brazil case.
app/controllers/my_profile/maps_controller.rb
... ... @@ -6,16 +6,51 @@ class MapsController < MyProfileController
6 6 @profile_data = profile
7 7 if request.post?
8 8 begin
  9 + national_code = nil
  10 + country = params[:profile_data][:country]
  11 + city = params[:profile_data][:city]
  12 + state = params[:profile_data][:state]
  13 +
  14 + nregion = NationalRegion.validate!(city, state, country)
  15 +
  16 + if nregion != nil
  17 + national_code = nregion.national_region_code
  18 + end
  19 +
  20 + params[:profile_data]["national_region_code"] = national_code
  21 +
9 22 Profile.transaction do
10 23 if profile.update_attributes!(params[:profile_data])
11 24 session[:notice] = _('Address was updated successfully!')
12 25 redirect_to :action => 'edit_location'
13 26 end
14 27 end
15   - rescue
16   - flash[:error] = _('Address could not be saved.')
  28 + rescue Exception => exc
  29 +
  30 + flash[:error] = exc.message
  31 +
17 32 end
18 33 end
19 34 end
20 35  
  36 + def search_city
  37 +
  38 + term = params[:term];
  39 +
  40 + regions = NationalRegion.search_city(term + "%", true).map {|r|{ :label => r.city , :category => r.state}}
  41 +
  42 + render :json => regions
  43 +
  44 + end
  45 +
  46 + def search_state
  47 +
  48 + term = params[:term];
  49 +
  50 + regions = NationalRegion.search_state(term + "%", true).map {|r|{ :label => r.state}}
  51 +
  52 + render :json => regions
  53 +
  54 + end
  55 +
21 56 end
... ...
app/models/national_region.rb 0 → 100644
... ... @@ -0,0 +1,71 @@
  1 +class NationalRegion < ActiveRecord::Base
  2 +
  3 + def self.search_city(city_name, like = false, state = nil)
  4 +
  5 + operator = "="
  6 + find_return = :first
  7 + adtional_contions = "";
  8 +
  9 + if like
  10 + operator = "like"
  11 + find_return = :all
  12 + end
  13 +
  14 + if state
  15 + adtional_contions = " AND nr.name = :state "
  16 + end
  17 +
  18 + conditions = ["national_regions.name #{operator} :name AND
  19 + national_regions.national_region_type_id = :type" + adtional_contions,
  20 + {:name => city_name ,
  21 + :type => NationalRegionType::CITY,
  22 + :state => state}];
  23 +
  24 + region = NationalRegion.find(find_return,
  25 + :select => "national_regions.name as city, nr.name as state, national_regions.national_region_code",
  26 + :conditions => conditions,
  27 + :joins => "LEFT JOIN national_regions as nr ON national_regions.parent_national_region_code = nr.national_region_code",
  28 + :limit => 10
  29 + )
  30 + return region
  31 + end
  32 +
  33 + def self.search_state(state_name, like = false)
  34 + operator = "="
  35 + find_return = :first
  36 +
  37 + if like
  38 + operator = "like"
  39 + find_return = :all
  40 + end
  41 +
  42 + conditions = ["national_regions.name #{operator} :name AND
  43 + national_regions.national_region_type_id = :type",
  44 + {:name => state_name,
  45 + :type => NationalRegionType::STATE}];
  46 +
  47 + region = NationalRegion.find(find_return,
  48 + :select => "national_regions.name as state, national_regions.national_region_code",
  49 + :conditions => conditions,
  50 + :limit => 10
  51 + )
  52 + return region
  53 + end
  54 +
  55 + def self.validate!(city, state, country)
  56 +
  57 + if(country == "BR")
  58 +
  59 + nregion = NationalRegion.search_city(city, false, state);
  60 +
  61 + if nregion == nil
  62 + raise _('Invalid city or state name.')
  63 + end
  64 +
  65 + end
  66 +
  67 + return nregion
  68 +
  69 + end
  70 +
  71 +end
... ...
app/models/national_region_type.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +class NationalRegionType < ActiveRecord::Base
  2 + COUNTRY = 1
  3 + STATE = 2
  4 + CITY = 3
  5 +end
... ...
app/views/maps/_google_map.rhtml
1   -<%= content_tag('script', '', :src => GoogleMaps.api_url(profile.default_hostname), :type => 'text/javascript') %>
  1 +<%= content_tag('script', '', :src => "http://maps.googleapis.com/maps/api/js?sensor=false", :type => 'text/javascript') %>
2 2  
3 3 <script type="text/javascript" >
  4 +
4 5 var geocoder;
5 6 var map;
6 7 var marker;
... ... @@ -8,11 +9,64 @@
8 9 var move = true;
9 10 var previousCenter;
10 11  
11   - function getAddress(overlay, latlng) {
  12 + function getAddress(latlng) {
12 13 $('location-fields').addClassName("loading");
13   - if (latlng != null) {
14   - geocoder.getLocations(latlng, showAddress);
  14 +
  15 + if (latlng != null) {
  16 + geocoder.geocode( {'latLng': latlng}, showAddress);
  17 + }
  18 + }
  19 +
  20 + function codeAddress() {
  21 + $('location-fields').addClassName("loading");
  22 +
  23 + var country_option = $('profile_data_country').value;
  24 + var address = $('profile_data_address').value + "-" + $('profile_data_zip_code').value + "," + $('profile_data_city').value+ "-" + $('profile_data_state').value + "," + country_option;
  25 +
  26 + if (geocoder) {
  27 + geocoder.geocode( { 'address': address}, function(results, status) {
  28 + if (status == google.maps.GeocoderStatus.OK) {
  29 + map.setCenter(results[0].geometry.location);
  30 + marker.setPosition(results[0].geometry.location);
  31 + $('profile_data_lat').value = results[0].geometry.location.lat();
  32 + $('profile_data_lng').value = results[0].geometry.location.lng();
  33 + $('location-fields').removeClassName("loading");
  34 + enable_save();
  35 + } else {
  36 + $('location-fields').removeClassName("loading");
  37 + alert('<%=_("Address not found, reason:")%>' + translate_status(status));
  38 + }
  39 + });
  40 + }
  41 +
  42 + return false;
  43 + }
  44 +
  45 + function translate_status(status)
  46 + {
  47 + var translated_status = '';
  48 +
  49 + if(google.maps.GeocoderStatus.INVALID_REQUEST == status)
  50 + {
  51 + translated_status = '<%= _('Invalid address') %>';
  52 + }
  53 +
  54 + if(google.maps.GeocoderStatus.REQUEST_DENIED == status)
  55 + {
  56 + translated_status = '<%= _('Request denied') %>';
  57 + }
  58 +
  59 + if(google.maps.GeocoderStatus.OVER_QUERY_LIMIT == status)
  60 + {
  61 + translated_status = '<%= _('Over query limit') %>';
15 62 }
  63 +
  64 + if(google.maps.GeocoderStatus.ZERO_RESULTS == status)
  65 + {
  66 + translated_status = "<%= _('Address do not exist') %>";
  67 + }
  68 +
  69 + return translated_status;
16 70 }
17 71  
18 72 function getAddressData() {
... ... @@ -33,104 +87,196 @@
33 87 return text;
34 88 }
35 89  
36   - function showAddress(response) {
37   - var message;
38   - place = geoCodeAddress(response);
39   - if ( place ) {
40   - if ( move ) {
41   - center = new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]);
42   - marker.setLatLng(center);
43   - } else {
44   - move = true;
45   - }
46   - message = showMessage(place);
47   - updateFields(place);
48   - } else {
49   - message = showNotFoundMessage();
50   - }
51   - map.addOverlay(marker);
52   - map.setCenter(marker.getLatLng());
53   - marker.openInfoWindowHtml(message, {maxWidth:300});
54   - }
  90 + function showAddress(results, status) {
  91 +
  92 + if (status == google.maps.GeocoderStatus.OK) {
  93 + map.setCenter(results[0].geometry.location);
  94 + updateFields(results[0]);
55 95  
56   - function geoCodeAddress(response) {
57   - if (!response || (response && response.Status.code != '200')) {
58   - return false;
59 96 } else {
60   - place = response.Placemark[0];
61   - return place;
  97 + alert("<%=_("Address not found, reason:")%>" + translate_status(status));
62 98 }
63   - }
64 99  
65   - function showMessage(place) {
66   - var message = '<b><%= _('Address:') %></b> ' + place.address + '<br>' +
67   - '<b><%= _('Coordinates:') %></b> ' + place.Point.coordinates[0] + "," + place.Point.coordinates[1] + '<br>' +
68   - '<b><%= _('Country code:') %></b> ' + place.AddressDetails.Country.CountryNameCode + '<br>';
69   - return message;
70 100 }
71 101  
72   - function showNotFoundMessage() {
73   - var message = '<%= _('Address not found') %>' + '<br>' +
74   - '<b><%= _('Coordinates:') %></b> ' + marker.getLatLng().lng() + "," + marker.getLatLng().lat();
75   - return message;
76   - }
77   -
78   - function updateFields(response) {
79   - var position = marker.getLatLng();
  102 + function updateFields(place) {
  103 + var position = marker.getPosition();
80 104 $('profile_data_lat').value = position.lat();
81 105 $('profile_data_lng').value = position.lng();
82 106 $('location-fields').removeClassName("loading");
83   - }
84 107  
85   - function loadMap() {
86   - if (GBrowserIsCompatible()) {
87   - map = new GMap2(document.getElementById("location-map"));
88   - geocoder = new GClientGeocoder();
89   - var lat = <%= profile.lat || 'false' %>;
90   - var lng = <%= profile.lng || 'false' %>;
91   - if ( lat && lng ) {
92   - center = new GLatLng( lat, lng );
93   - continueLoadMap();
94   - } else {
95   - geocoder.getLocations('<%= profile.geolocation %>', loadAddress);
96   - }
  108 + var components_len = place.address_components.size();
  109 +
  110 + if(components_len < 2)
  111 + {
  112 + return false;
  113 + }
  114 +
  115 + var components = place.address_components;
  116 + var address = "";
  117 + var zip_code = "";
  118 + var city = "";
  119 + var state = "";
  120 + var country_code = "";
  121 + var i = 0;
  122 +
  123 + for( i =0 ; i < components_len; i ++)
  124 + {
  125 +
  126 + if(components[i].types[0] == 'country')
  127 + {
  128 + country_code = components[i].short_name;
  129 + }
  130 +
  131 + if(components[i].types[0] == 'administrative_area_level_1')
  132 + {
  133 + state = components[i].long_name;
  134 + }
  135 +
  136 + if(components[i].types[0] == 'locality')
  137 + {
  138 + city = components[i].long_name;
  139 + }
  140 +
  141 + if(components[i].types[0] == 'sublocality')
  142 + {
  143 + address = components[i].long_name + "-" + address;
  144 + }
  145 +
  146 + if(components[i].types[0] == "route")
  147 + {
  148 + address = components[i].long_name + address;
  149 + }
  150 +
  151 +
  152 + if(components[i].types[0] == "street_number")
  153 + {
  154 + address = address + "," + components[i].short_name ;
  155 + }
  156 +
  157 + if(components[i].types[0] == 'postal_code')
  158 + {
  159 + zip_code = components[i].short_name;
  160 + }
  161 +
97 162 }
  163 +
  164 + $('profile_data_country').value = country_code;
  165 + $('profile_data_state').value = state;
  166 + $('profile_data_address').value = address;
  167 + $('profile_data_city').value = city;
  168 + $('profile_data_zip_code').value = zip_code;
98 169 }
99 170  
100   - function loadAddress(response) {
101   - place = geoCodeAddress(response);
102   - if ( move ) {
103   - center = new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]);
  171 +
  172 + function initialize_map() {
  173 + geocoder = new google.maps.Geocoder();
  174 +
  175 + var lat = <%= profile.lat || 'false' %>;
  176 + var lng = <%= profile.lng || 'false' %>;
  177 +
  178 + if ( !(lat && lng) ) {
  179 + lat = -15.7605361485013;
  180 + lng = -47.933349609375;
  181 + }
  182 +
  183 + var latlng = new google.maps.LatLng(lat,lng);
  184 +
  185 + var myOptions = {
  186 + zoom: 8,
  187 + center: latlng,
  188 + mapTypeId: google.maps.MapTypeId.ROADMAP
104 189 }
105   - continueLoadMap();
  190 +
  191 + center = latlng;
  192 +
  193 + map = new google.maps.Map(document.getElementById("location-map"), myOptions);
  194 +
  195 + continueLoadMapV3()
106 196 }
107 197  
108   - function continueLoadMap() {
109   - marker = new GMarker(center, {draggable: true});
110   - map.setCenter(center, 4);
  198 + function continueLoadMapV3() {
  199 +
  200 + marker = new google.maps.Marker({
  201 + position: center,
  202 + map: map,
  203 + draggable: true
  204 + });
  205 +
  206 + google.maps.event.addListener(marker, "dragend", function() {
  207 + move = false;
  208 + getAddress(marker.getPosition());
  209 + });
  210 +
  211 + }
  212 +
  213 + window.onload = initialize_map;
  214 +
  215 + var delay_autocomplete = 500;
  216 +
  217 + jQuery.noConflict();
  218 + jQuery(document).ready(function (){
  219 +
  220 + jQuery.widget( "custom.catcomplete",jQuery.ui.autocomplete, {
  221 + _renderMenu: function( ul, items ) {
  222 + var self = this,
  223 + currentCategory = "";
  224 + jQuery.each( items, function( index, item ) {
  225 + if ( item.category != currentCategory ) {
  226 + ul.append( "<li class='ui-autocomplete-category'>" + item.category + "</li>" );
  227 + currentCategory = item.category;
  228 + }
  229 + self._renderItem( ul, item );
  230 + });
  231 + }
  232 + });
111 233  
112   - map.addControl(new GLargeMapControl());
113   - map.addControl(new GScaleControl());
114   - map.addControl(new GMapTypeControl());
115 234  
116   - GEvent.addListener(marker, "dragstart", function() {
117   - previousCenter = marker.getLatLng();
118   - map.closeInfoWindow();
  235 + jQuery("#profile_data_city").catcomplete({
  236 + source: "../maps/search_city",
  237 + minLength: 3,
  238 + delay: delay_autocomplete,
  239 + select: function( event, ui ) { $('profile_data_state').value =( ui.item ? ui.item.category : this.value ); }
119 240 });
120 241  
121   - GEvent.addListener(marker, "dragend", function() {
122   - move = false;
123   - getAddress(overlay, marker.getLatLng());
  242 + jQuery("#profile_data_state").autocomplete({
  243 + source: "../maps/search_state",
  244 + minLength: 3,
  245 + delay: delay_autocomplete
124 246 });
125 247  
126   - GEvent.addListener(marker, "click", function() {
127   - move = false;
128   - getAddress(overlay, marker.getLatLng());
  248 + jQuery("#profile_data_city").keyup(function(){
  249 +
  250 + disable_save();
  251 +
129 252 });
130 253  
131   - map.addOverlay(marker);
132   - }
  254 + jQuery("#profile_data_state").keyup(function(){
  255 +
  256 + disable_save();
  257 +
  258 + });
133 259  
134   - window.onload = loadMap;
135   - window.unload = GUnload();
  260 + jQuery("#profile_data_country").change(function(){
  261 +
  262 + disable_save();
  263 +
  264 + });
  265 +
  266 + });
  267 +
  268 + function disable_save()
  269 + {
  270 + jQuery('input[type="submit"]').attr("disabled", "true");
  271 + jQuery('input[type="submit"]').attr("value", '<%=_("Localize before save")%>');
  272 + jQuery('input[type="submit"]').attr("class", "disabled button icon-save submit");
  273 + }
  274 + function enable_save()
  275 + {
  276 + jQuery('input[type="submit"]').attr("value", '<%=_("Save")%>');
  277 + jQuery('input[type="submit"]').removeAttr("disabled");
  278 + jQuery('input[type="submit"]').attr("class", "button icon-save submit");
  279 + }
136 280 </script>
  281 +
  282 +
... ...
app/views/maps/edit_location.rhtml
1 1 <h1><%= _('Location') %></h1>
2   -
  2 +<div class="error">
  3 + <%= flash[:error] %>
  4 +</div>
3 5 <% form_for :profile_data, :url => {:action => 'edit_location'} do |f| %>
4 6  
5 7 <div id='location-fields'>
... ... @@ -9,26 +11,25 @@
9 11 <%= optional_field(profile, 'zip_code', labelled_form_field(_('ZIP code'), text_field(:profile_data, :zip_code))) %>
10 12 <%= optional_field(profile, 'address', labelled_form_field(_('Address (street and number)'), text_field(:profile_data, :address))) %>
11 13 <% button_bar do %>
12   - <%= button_to_function :search, _('Locate in the map'), "getAddress(null, getAddressData())", :title => _("Locate the address informed above in the map below (note that you'll probably need to adjust the marker to get a precise position)") %>
  14 + <%= button_to_function :search, _('Locate in the map'), "codeAddress()", :title => _("Locate the address informed above in the map below (note that you'll probably need to adjust the marker to get a precise position)") %>
13 15 <%= submit_button 'save', _('Save') %>
14 16 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
15 17 <% end %>
16 18 </div>
17 19  
18   -
19 20 <div style='overflow: hidden'>
20 21 <p><div id="location-map"></div></p>
21 22 </div>
22 23  
23 24 <%= f.hidden_field(:lat) %>
24 25 <%= f.hidden_field(:lng) %>
25   -
26   -
  26 +
27 27  
28 28 <% button_bar do %>
29 29 <%= submit_button 'save', _('Save') %>
30 30 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
31 31 <% end %>
  32 +
32 33  
33 34 <% end %>
34 35  
... ...
db/migrate/20110726115751_add_national_region_code_to_profiles.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddNationalRegionCodeToProfiles < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :profiles, :national_region_code, :string, :null => true
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :profiles, :national_region_code
  8 + end
  9 +end
... ...
db/migrate/20110726121110_create_national_regions.rb 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +class CreateNationalRegions < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :national_regions do |t|
  4 + t.string :name
  5 + t.string :national_region_code
  6 + t.string :parent_national_region_code
  7 +
  8 + t.timestamps
  9 + end
  10 +
  11 + add_index(:national_regions, :national_region_code, {:name => "code_index"})
  12 + add_index(:national_regions, :name, {:name => "name_index"})
  13 + end
  14 +
  15 + def self.down
  16 + drop_table :national_regions
  17 + end
  18 +end
... ...
db/migrate/20110729130724_national_region_types.rb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +class NationalRegionTypes < ActiveRecord::Migration
  2 + def self.up
  3 + create_table :national_region_types do |t|
  4 + t.string :name
  5 + end
  6 +
  7 + NationalRegionType.create :name => "Country"
  8 + NationalRegionType.create :name => "State"
  9 + NationalRegionType.create :name => "City"
  10 +
  11 + end
  12 +
  13 + def self.down
  14 + drop_table :national_region_types
  15 + end
  16 +end
... ...
db/migrate/20110729130913_add_region_type_id_to_national_regions.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddRegionTypeIdToNationalRegions < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :national_regions, :national_region_type_id, :integer, :null => false
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :national_regions, :national_region_type_id
  8 + end
  9 +end
... ...
public/stylesheets/application.css
... ... @@ -5640,3 +5640,13 @@ h1.page-title.no-boxes small {
5640 5640 .clearfix:after {
5641 5641 clear: both;
5642 5642 }
  5643 +
  5644 +/* AutoComplete*/
  5645 +.formfield input.ui-autocomplete-loading { background: url('/images/loading-small.gif') right center no-repeat, url("../images/input-bg.gif") no-repeat left top; }
  5646 +
  5647 +.ui-autocomplete-category {
  5648 + font-weight: bold;
  5649 + padding: .2em .4em;
  5650 + margin: .8em 0 .2em;
  5651 + line-height: 1.5;
  5652 +}
... ...
test/functional/maps_controller_test.rb
... ... @@ -22,6 +22,31 @@ class MapsControllerTest &lt; ActionController::TestCase
22 22 assert_equal 'new address', Profile['test_profile'].address
23 23 end
24 24  
  25 + should 'save profile national_region_code' do
  26 +
  27 + national_region_code = '355030'
  28 + city = 'Santo Afonso'
  29 + state = 'Mato Grosso'
  30 +
  31 + parent_region = fast_create(NationalRegion, :name => state,
  32 + :national_region_code => '35',
  33 + :national_region_type_id => NationalRegionType::STATE)
  34 +
  35 + fast_create(NationalRegion, :name => city,
  36 + :national_region_code => national_region_code,
  37 + :national_region_type_id => NationalRegionType::CITY,
  38 + :parent_national_region_code => parent_region.national_region_code)
  39 +
  40 + post :edit_location, :profile => profile.identifier, :profile_data => {
  41 + :address => 'new address',
  42 + :country => 'BR',
  43 + :city => city,
  44 + :state => state
  45 + }
  46 +
  47 + assert_equal national_region_code, Profile['test_profile'].national_region_code
  48 + end
  49 +
25 50 should 'back when update address fail' do
26 51 Profile.any_instance.stubs(:update_attributes!).returns(false)
27 52 post :edit_location, :profile => profile.identifier, :profile_data => { 'address' => 'new address' }
... ... @@ -45,13 +70,47 @@ class MapsControllerTest &lt; ActionController::TestCase
45 70 assert_tag :tag => 'input', :attributes => { :name => 'profile_data[city]' }
46 71 end
47 72  
48   - should 'add script tag for google maps' do
49   - domain = fast_create(Domain, :name => 'domain-with-key', :google_maps_key => 'DOMAIN_KEY')
50   - profile.preferred_domain = domain
51   - profile.save!
  73 + should 'autocomplete search_city' do
  74 +
  75 + city = 'Santo Afonso'
  76 + state = 'Mato Grosso'
  77 +
  78 + parent_region = fast_create(NationalRegion, :name => state,
  79 + :national_region_code => '35',
  80 + :national_region_type_id => NationalRegionType::STATE)
  81 +
  82 + fast_create(NationalRegion, :name => city,
  83 + :national_region_code => '355030',
  84 + :national_region_type_id => NationalRegionType::CITY,
  85 + :parent_national_region_code => parent_region.national_region_code)
  86 +
  87 + get :search_city, :term => "San", :profile => profile.identifier
  88 +
  89 + json_response = ActiveSupport::JSON.decode(@response.body)
  90 +
  91 + label = json_response[0]['label']
  92 + category = json_response[0]['category']
  93 +
  94 + assert_equal city, label
  95 + assert_equal state, category
  96 + end
  97 +
  98 + should 'autocomplete search_state' do
  99 +
  100 + state = 'Mato Grosso do Sul'
  101 +
  102 +
  103 + fast_create(NationalRegion, :name => state,
  104 + :national_region_code => '36',
  105 + :national_region_type_id => NationalRegionType::STATE)
  106 +
  107 +
  108 + get :search_state, :term => "Mat", :profile => profile.identifier
  109 +
  110 + json_response = ActiveSupport::JSON.decode(@response.body)
52 111  
53   - get 'edit_location', :profile => profile.identifier
  112 + label = json_response[0]['label']
54 113  
55   - assert_tag :tag => 'script', :attributes => { :src => 'http://maps.google.com/maps?file=api&amp;v=2&amp;key=DOMAIN_KEY'}
  114 + assert_equal state, label
56 115 end
57 116 end
... ...
test/unit/national_region_test.rb 0 → 100644
... ... @@ -0,0 +1,70 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class NationalRegionTest < ActiveSupport::TestCase
  4 +
  5 + should 'search_city especific city' do
  6 + city_name = "Santos"
  7 +
  8 + new_region = fast_create(NationalRegion, :name => city_name,
  9 + :national_region_code => '355030',
  10 + :national_region_type_id => NationalRegionType::CITY)
  11 +
  12 + found_region = NationalRegion.search_city(city_name)
  13 +
  14 + assert_equal new_region.name, found_region.city
  15 + assert_equal new_region.national_region_code, found_region.national_region_code
  16 + end
  17 +
  18 + should 'search_city like cities' do
  19 + city_names = [ "Santo Afonso", "Santo Antonio", "Santo Augusto" ]
  20 + new_regions = []
  21 +
  22 + for i in 0..city_names.length
  23 + new_regions << fast_create(NationalRegion, :name => city_names[i],
  24 + :national_region_code => '355030',
  25 + :national_region_type_id => NationalRegionType::CITY)
  26 + end
  27 +
  28 + found_regions = NationalRegion.search_city('Santo %', true)
  29 +
  30 + assert !(found_regions.length != 3)
  31 +
  32 + found_regions.each do |region|
  33 + assert city_names.find_index(region.city) >= 0
  34 + end
  35 +
  36 + end
  37 +
  38 + should 'search_city especific state' do
  39 + state_name = "Santa Catarina"
  40 +
  41 + new_region = fast_create(NationalRegion, :name => state_name,
  42 + :national_region_code => '22',
  43 + :national_region_type_id => NationalRegionType::STATE)
  44 +
  45 + found_region = NationalRegion.search_state(state_name)
  46 +
  47 + assert_equal new_region.name, found_region.state
  48 + assert_equal new_region.national_region_code, found_region.national_region_code
  49 + end
  50 +
  51 + should 'search_city like states' do
  52 + state_names = [ "Rio de Janeiro", "Rio Grande do Norte", "Rio Grande do Sul" ]
  53 + new_regions = []
  54 +
  55 + for i in 0..state_names.length
  56 + new_regions << fast_create(NationalRegion, :name => state_names[i],
  57 + :national_region_code => '35',
  58 + :national_region_type_id => NationalRegionType::STATE)
  59 + end
  60 +
  61 + found_regions = NationalRegion.search_state('Rio %', true)
  62 +
  63 + assert !(found_regions.length != 3)
  64 +
  65 + found_regions.each do |region|
  66 + assert state_names.find_index(region.state) >= 0
  67 + end
  68 +
  69 + end
  70 +end
... ...