Topic: Integrate google maps: Cartographer v YM4R

Hello, I need to integrate GMaps into my app in two ways:

1. Users need to be able to search for things near them (I have a "What" and "Where" search box)
2. The results are then shown as a list, but the user can choose to also display the results on a map.

I've seen both Cartographer and YM4R. Whats the difference, and what would be better in this situation?

Also, I have no idea how to convert addresses to coordinates, so which plugin will help me with that?

Thanks
-Amir

Last edited by amoo3 (2007-06-20 11:33:49)

Re: Integrate google maps: Cartographer v YM4R

I've no experience with either Cartographer v YM4R.

I found it's so horribly easy to integrate Google Maps using the wizard:
http://www.google.com/uds/solutions/wiz … earch.html

For example, you just change the actual address on the code below and you wouldnt need to worry about coordinates:

<!-- ++Begin Map Search Control Wizard Generated Code++ -->
  <!--
  // Created with a Google AJAX Search Wizard
  // http://code.google.com/apis/ajaxsearch/wizards.html
  -->

  <!--
  // The Following div element will end up holding the map search control.
  // You can place this anywhere on your page
  -->
  <div id="mapsearch">
    <span style="color:#676767;font-size:11px;margin:10px;padding:4px;">Loading...</span>
  </div>

  <!-- Maps Api, Ajax Search Api and Stylesheet
  // Note: If you are already using the Maps API then do not include it again
  //       If you are already using the AJAX Search API, then do not include it
  //       or its stylesheet again
  //
  // The Key Embedded in the following script tags is designed to work with
  // the following site:
  // http://carmelyne.com
  -->
  <script src="http://maps.google.com/maps?file=api&v=2&key=ABQIAAAAZFJWpftMwgnCCqt4vPRS7BR_ZcIL7pO4iYyfFpBmAPGFfFx64hSpMeeCW2KZJX-EMwFvmwfpYTE7Rw"
    type="text/javascript"></script>
  <script src="http://www.google.com/uds/api?file=uds.js&v=1.0&source=uds-msw&key=ABQIAAAAZFJWpftMwgnCCqt4vPRS7BR_ZcIL7pO4iYyfFpBmAPGFfFx64hSpMeeCW2KZJX-EMwFvmwfpYTE7Rw"
    type="text/javascript"></script>
  <style type="text/css">
    @import url("http://www.google.com/uds/css/gsearch.css");
  </style>

  <!-- Map Search Control and Stylesheet -->
  <script type="text/javascript">
    window._uds_msw_donotrepair = true;
  </script>
  <script src="http://www.google.com/uds/solutions/mapsearch/gsmapsearch.js?mode=new"
    type="text/javascript"></script>
  <style type="text/css">
    @import url("http://www.google.com/uds/solutions/mapsearch/gsmapsearch.css");
  </style>

  <style type="text/css">
    .gsmsc-mapDiv {
      height : 275px;
    }

    .gsmsc-idleMapDiv {
      height : 275px;
    }

    #mapsearch {
      width : 365px;
      margin: 10px;
      padding: 4px;
    }
  </style>
  <script type="text/javascript">
    function LoadMapSearchControl() {

      var options = {
            zoomControl : GSmapSearchControl.ZOOM_CONTROL_ENABLE_ALL,
            title : "Googleplex",
            url : "http://www.google.com/corporate/index.html",
            idleMapZoom : GSmapSearchControl.ACTIVE_MAP_ZOOM,
            activeMapZoom : GSmapSearchControl.ACTIVE_MAP_ZOOM,
            showResultList : GSmapSearchControl.DEFAULT_RESULT_LIST
            }

      new GSmapSearchControl(
            document.getElementById("mapsearch"),
            //CHANGE THE ADDRESS HERE
            "1600 Amphitheatre Parkway, Mountain View, CA",
            options
            );

    }
    // arrange for this function to be called during body.onload
    // event processing
    GSearch.setOnLoadCallback(LoadMapSearchControl);
  </script>
<!-- ++End Map Search Control Wizard Generated Code++ -->


With the code above, you can search places near the area and the results are shown right below the map and marked on the actual map image.

If the above code doesnt suit you, here's a good reference site that's all about Google Maps and it's implementations: http://www.econym.demon.co.uk/googlemaps/index.htm

Last edited by carmelyne (2007-06-20 13:28:27)

<= Will buy you beer for some Ruby Help

Re: Integrate google maps: Cartographer v YM4R

Graticule and its acts_as_geocodable plugin are the best choice IMO.

Re: Integrate google maps: Cartographer v YM4R

Wow, acts_as_geocodalbe looks cool. What I've seen so far, it seems like I can implement this into my ferret search engine and filter the results?

Re: Integrate google maps: Cartographer v YM4R

Yea, you can refine your ferret search with this. Do the geo-search first and then pass the results to the find_by_contents as 3rd parameter (find_options). That should work fine.

Re: Integrate google maps: Cartographer v YM4R

So I installed the geocode gem and acts_as_geocodable plugin, but when i try to rake I get "uninitialized constant Geocode."

When i try to start the server I get

/usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:266:in `load_missing_constant': uninitialized constant Geocode (NameError)
        from /usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:452:in `const_missing'
        from /usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:464:in `const_missing'
        from /Users/amir/Projects/auto/config/environment.rb:11
        from /usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
        from /usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
        from /usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require'
        from /usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:342:in `new_constants_in'
        from /usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/dependencies.rb:495:in `require'
         ... 21 levels...
        from /usr/local/lib/ruby/gems/1.8/gems/rails-1.2.3/lib/commands/server.rb:39
        from /usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
        from /usr/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require'
        from script/server:3

How can I fix this?

Ok, When I change my environment.rb from

 Geocode.geocoder = Graticule.service(:google).new 'my_api_key'

to
 geocoder = Graticule.service(:google).new 'my_key'

The rake error now says "uninitialized constant Graticule"

FIXED! I forgot to add the requires....Figures.

Last edited by amoo3 (2007-06-21 22:15:29)

Re: Integrate google maps: Cartographer v YM4R

rudionrails wrote:

Yea, you can refine your ferret search with this. Do the geo-search first and then pass the results to the find_by_contents as 3rd parameter (find_options). That should work fine.

Im not sure what you mean. can you please elaborate. What I have right now is one search box that works with the following code, and one (where) search box that currently does nothing.

def search
    @q = params[:q]
    @vehicle = Vehicle.find_by_contents(@q)
    @hits = Vehicle.total_hits(@q)   
    self.add_to_recent_searches
  end

I know that I'll be doing something like
@locations = location.find(:all, :within => 50, :origin => params[:where])

The user is searching for a car (The vehicle model) which has a location_id, which is what the geocoding is searching. I am unsure where to go from here.

Many Thanks
-Amir

Last edited by amoo3 (2007-06-21 22:58:10)

Re: Integrate google maps: Cartographer v YM4R

Regarding your previous post, do you have this in your environment.rb?

require 'graticule'

EDIT: Oops... just recognised you already found out smile

Regarding your second post:
If you go into your plugins folder and check acts_as_ferret, go into lib/ and open instance_methods.rb. Look for the function "find_by_contents". You will notice that you can pass more values to it than just the string query.

If you want to combine your Geo-search with Ferret on the basis of your models (Vehicle and Location), then it could look like the following:

# make your geo search first for finding the range of locations
location_ids = Location.find(:all, :within => 50, :origin => params[:where]).map(&:id).join(',')

# after you have a comma-separated list of ids, execute your ferret search
# first specify your additional conditions
conditions = "location_id IN (#{location_ids})" unless location_ids.empty?

# perform your search
@vehicles = Vehicle.find_by_contents( params[:q],
                  { },
                  { :conditions => conditions } )

# no need to perform a Ferret search again, you get that "for free" already
@total_hits = @vehicles.total_hits


You can perform this search in a different way as well. They way it's written here, I would use it in my search controller. You can also do this in your model directly. You might want to have a look at the Lucene Query Syntax to learn in which ways you can perform searches or have a look at this very popular acts_as_ferret tutorial.

I hope that helps.

Last edited by rudionrails (2007-06-22 05:44:53)

Re: Integrate google maps: Cartographer v YM4R

Thanks alot Rudio, however I am getting an error:

 NoMethodError in Auto searchController#search

You have a nil object when you didn't expect it!
The error occurred while evaluating nil.locate

RAILS_ROOT: script/../config/..
Application Trace | Framework Trace | Full Trace

vendor/plugins/acts_as_geocodable/lib/geocode.rb:25:in `create_by_query'
vendor/plugins/acts_as_geocodable/lib/geocode.rb:21:in `find_or_create_by_query'
vendor/plugins/acts_as_geocodable/lib/acts_as_geocodable.rb:97:in `location_to_geocode'
vendor/plugins/acts_as_geocodable/lib/acts_as_geocodable.rb:78:in `find'
app/controllers/auto_search_controller.rb:8:in `search'


The error originates from this line of code:
location_ids = Location.find(:all, :within => 50, :origin => params[:where]).map(&:id).join(',')

I have the acts_as_geoodable line in my model.
Anyone know whats wrong?

Last edited by amoo3 (2007-06-22 18:48:14)

Re: Integrate google maps: Cartographer v YM4R

Ok, I fixed that error, but now I have a new one:

 SyntaxError in Auto searchController#search

app/controllers/auto_search_controller.rb:12: odd number list for Hash
      @vehicle = Vehicle.find_by_contents(@q, {}, {conditions })


Also, Rudio, what was the :conditions for? It threw a MYSQL error if I used that.

Thanks
-Amir
                                                               ^

Re: Integrate google maps: Cartographer v YM4R

:conditions is merely an SQL statement to filter your search.

you can do something like this with it

@vehicles = Vehicle.find_by_contents( params[:q],
                 { :limit => 100 }, # limit your search results to 100
                 { :conditions => "location_id IN (1, 2, 3)"} ) # performs the search only for vehicles with location_id of 1, 2, and 3.

Like I said, it is worth it to have a look into vendor/plugins/acts_as_ferret/lib/instance_methods.rb. You will get a better understanding if you have a look at the find_by_contents method.

Last edited by rudionrails (2007-06-23 09:07:29)

Re: Integrate google maps: Cartographer v YM4R

Hi Amoo3, How did you fix the nil.locate error?
I am having the same difficulties and your help would be much appreciated.

Re: Integrate google maps: Cartographer v YM4R

I would love to hear any feedback you have for improving Graticule and acts_as_geocodable.

Re: Integrate google maps: Cartographer v YM4R

Sorry, got it.
Had to add something like  this to the update method incase anyone else is interested,

    g = Graticule.service(:local_search_maps).new
    location = g.locate(params[:address])

daah!

Re: Integrate google maps: Cartographer v YM4R

No, actually i am still getting same error.
Damn it!

Re: Integrate google maps: Cartographer v YM4R

Ah, Brandon, your a developer!
Do you know why graticule is not finding many locations(that do exist).  I am looking
for locations in Australia. For example

>>location = g.locate :region => "VIC", :country => "AUS", :locality => "Melbourne", :street => ""
=> #<Graticule::Location:0x4482c78 @precision=:unknown, @longitude=145.0, @latit
ude=-37.833302>

But if I add a "street" value it returns "location not found"
>>location = g.locate :region => "VIC", :country => "AUS", :locality => "Melbourne", :street => "Queen St"

Graticule::AddressError: Location not found
        from C:/INSTAN~1/ruby/lib/ruby/gems/1.8/gems/graticule-0.2.4/lib/graticu
le/geocoder/local_search_maps.rb:32:in `check_error'
        from C:/INSTAN~1/ruby/lib/ruby/gems/1.8/gems/graticule-0.2.4/lib/graticu
le/geocoder/base.rb:80:in `get'
        from C:/INSTAN~1/ruby/lib/ruby/gems/1.8/gems/graticule-0.2.4/lib/graticu
le/geocoder/local_search_maps.rb:17:in `locate'
        from (irb):49


EDIT; Ok, so now it is findiing "Queen St", I'm confused?  BTW, any help on nil.locate? Sorry, I sound like a nag.

Last edited by jo s (2007-07-01 04:24:34)

Re: Integrate google maps: Cartographer v YM4R

Jo s, I've found geocoder to be quite a pain to use, and have switched over to GeoKit (http://geokit.rubyforge.org/)
So far everything works fine. I can search for a location and it will return an array of locations within a given radius. All I have left to do is actually filter the ferret results.

Last edited by amoo3 (2007-07-02 02:14:36)

Re: Integrate google maps: Cartographer v YM4R

Geocoder is a light alternative for Graticule. However, Graticule supports more mapping API's and, most importantly, has better support outside the US smile

Re: Integrate google maps: Cartographer v YM4R

rudi, the main problem I had with acts_as_geocodable was that I had pluralization turned off, and the plugin did not seem to support that.

Last edited by amoo3 (2007-07-02 12:04:03)

Re: Integrate google maps: Cartographer v YM4R

So I've got all my code looking like it should work, but @vehcles is still turning up as nil. Heres my code:

@location = Location.find_within(10, :origin => '20904')
    conditions = "location_id IN (#{@location.id})" unless @location.empty?
     
    # perform your search
    @vehicles = Vehicle.find_by_contents( params[:q],
                     { },
                     { :conditions => conditions } )

I have also tried
@location = Location.find_within(10, :origin => '20904')
    conditions = "location_id IN (#{@location.id})" unless @location.empty?
     
    # perform your search
    @vehicles = Vehicle.find_by_contents( params[:q],
                     { },
                     { :conditions => "location_id IN (1,2)" } )

and got the same results. Any idea whats wrong?

Last edited by amoo3 (2007-07-02 13:08:55)