Project

us_zipcode

0.0
No commit activity in last 3 years
No release in over 3 years
A Ruby gem for looking up and manipulating US postal codes and geocodes.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

~> 0.11.0
>= 3.0.0
 Project Readme

Us Zip Code

Simple gem to handle zipcode lookups and related functionality. rake zipcodes:update will automatically download and update your local zipcode database. Generates three models for extended zipcode functionality.

Installation

Add the following line to your Gemfile:

gem 'us_zipcode'

Run:

bundle install

Generate the models and populate the data:

rails g us_zipcode:models
rake db:migrate
rake zipcodes:update

You should now have three new tables and three new models, Zipcode, State, County.

Usage

zipcode = Zipcode.find_by_code '66206'
zipcode.state.abbr    # => 'KS'
zipcode.city          # => 'Shawnee Mission'
zipcode.county.name   # => 'Johnson'
zipcode.lat.to_s      # => '38.959356', it is actually a BigDecimal object converted to_s for documentation.
zipcode.lon.to_s      # => '-94.716155', ditto
zipcode.is_geocoded?  # => true, most if not all should be pre-geocoded.

You can use State and County objects as follows:

state = State.find_by_abbr "MO"
state.cities.count    # => 963
state.cities          # gives you a sorted array of all cities for the state
state.zipcodes.count  # => 1195
...
county = state.counties.first
county.cities.count   # => 5
county.cities         # gives you a sorted array of all cities for the county
county.zipcodes.count # => 5

Look Up City by State & zip code + county by city

First you have to select a state .On state selection , you can see the cities drop down which are associated with the selected state.
On city selection, you can see the corresponding county with its zip code.

Write the following code in your view:

<%= select_tag "state",options_from_collection_for_select(State.all, "id", "name") %>
<div id ="city"></div>
<div id ="county"></div>
<script>
  $("#state").on("change", function () {
    $.ajax({
      url: "/mycontroller/get_cities_by_state",
      dataType: "script",
      method: "get",
      data: {state_id: $(this).val()}
    });
    $("#county").html('');
  });
</script> 

Create mycontroller & paste the following code:

def get_cities_by_state
    @cities = Zipcode.group(:city).where(state_id: params[:state_id])
  end
 def get_county_and_zip_by_city    
    @zipcodes = Zipcode.find_by_city(params[:city])
  end

Create the following two js.erb files in app/views/mycontroller/

1.get_cities_by_state.js.erb & paste the following code:

$("#city").html('<%= escape_javascript(select_tag "city", options_from_collection_for_select(@cities, :id, :city)) %>');
$("#city").on("change", function(){
  $.ajax({
    url: "/mycontroller/get_county_and_zip_by_city",
    dataType: "script",
    method: "get",
    data: {city: $("#city select option:selected"). text()}
  });
});

2.get_county_and_zip_by_city.js.erb

$("#county").html('<%= escape_javascript(select_tag "county", options_from_collection_for_select(@zipcodes, :id, :county_and_zip)) %>');

In the last update your routes:

scope '/mycontroller' do
     get 'get_cities_by_state' => 'mycontroller#get_cities_by_state'
     get 'get_county_and_zip_by_city' => 'mycontroller#get_county_and_zip_by_city'
    end

Automatic JQuery/AJAX lookup

You can have a user enter a zipcode and automatically lookup their city, state and county.

Put something like this in your view:

f.text_field :zip, :size => 5, :maxlength => 5, :class => 'zipcode_interactive'
f.text_field :city, :size => 20, :maxlength => 60, :readonly => true
f.text_field(:state, :size => 2, :maxlength => 2, :readonly => true)
f.text_field(:county, :size => 20, :maxlength => 60, :readonly => true)

Then add this to your application.js, but remember to replace [mycontrollername] with your own controller.

   $(document).ready(function() {
        // Interactive Zipcodes
        $('input.zipcode_interactive').blur(function(data) {
            var elem_id = $(this).attr("id");
            var base_id = elem_id.substring(0, elem_id.lastIndexOf("_"));
            $.get("/mycontrollername/get_zip_data/" + this.value, {},
            function(data) {
                var zipcode = $.parseJSON(data);
                var city = $('#' + base_id + '_city');
                var state = $('#' + base_id + '_state');
                var county = $('#' + base_id + '_county');
                if (zipcode.err) {
                    alert(zipcode.err);
                } else {
                    city.val(zipcode.city);
                    state.val(zipcode.state)
                    county.val(zipcode.county)
                }
            })
        });
    });

You will also need a controller method similar to this, which will return the data to your form:

   def get_zip_data
      @zipcode = Zipcode.find_by_code(params[:code], :include => [:county, :state])
      if @zipcode
        @counties = County.find(:all, :conditions => [ "state_id = ?", @zipcode.county.state_id ])
        data = {
          'state' => @zipcode.state.abbr,
          'county' => @zipcode.county.name,
          'city' => @zipcode.city.titleize
        }
        render :text => data.to_json
      else
        if params[:code].blank?
          return true
        else
          if params[:code].is_zipcode?
            data = {
              'err' => "Could not find Zipcode [#{params[:code]}].  If this is a valid zipcode please notify support <support@mydomain.com>, so we can update our database."
            }
          else
            data = {
              'err' => "[#{params[:code]}] is not a valid Zipcode."
            }
          end
          render :text => data.to_json
        end
      end
    end

And define a route for the AJAX function in routes.rb:

get 'mycontrollername/get_zip_data/:code', :controller => 'mycontrollername', :action => 'get_zip_data'

That’s about it.

Let me know if there are any errors. I cut and pasted the code above from a working application, but there may be some gotchas that I missed.