The major part of my experiment was going to be the integration with Google Maps. At first, I was a bit apprehensive about it, but Ruby on Rails being a community oriented language, I found a couple of quite useful plug-ins. With them, finding a location based on address or geocode or finding nearby places based on certain radius of a location were not too hard.
There is actually an excellent book also, called Beginning Google maps applications with Rails and Ajax. But the problem with the book is that it was geared towards more for java developers using rails. Thus, its major functions were javascripts and it showed how to talk to rails app. In my case, since I wanted simple features and I didn’t want to take time to learn javascript, I decided to find a simpler way.
And I found that for things I wanted to do, I could do with YM4R/GM and Geokit. There are other excellent tutorials out there like the one by Jason Gilmore on Developer.com.
Let’s begin.
1. Sign-up for Google Maps API by going to here. For development environment, you can use either http://localhost:3000 or http://127.0.0.1:300 as the website URL. Copy the API key.
When you move to production environment, make sure you come back here to get another key for production URL.
2. Install YM4R/GM. From your rails app root directory,
ruby script/plugin install svn://rubyforge.org/var/svn/ym4r/Plugins/GM/trunk/ym4r_gm
2.1. Edit the config/gmap_api_key.yml and put your API key in the development section.
development:
[Your development API KEY]
test:
[Your development API KEY]
production:
[Your production API KEY]
3. Install Geokit for Rails. From your rails app root directory,
script/plugin install git://github.com/andre/geokit-rails.git
Also add the following line inside Rails::Initializer.run do |config| in config/environment.rb.
Rails::Initializer.run do |config|
[OTHER CODES]
config.gem "geokit"
end
Last, install the gem.
rake gems:install
3.1. Add lat and lng fields to your database using migration. I am using my controller as an example, so substitute it with your controller.
ruby script/generate migration AddGeoToPlaygrounds
Then edit the migration file.
class AddGeoToPlaygrounds < ActiveRecord::Migration
def self.up
add_column :playgrounds, :lat, :float
add_column :playgrounds, :lng, :float
end
def self.down
remove_column :playgrounds, :lat
remove_column :playgrounds, :lng
end
end
3.2. Do rake db:migrate, and now you are ready to put Google Maps in your rails app.
4. Find a location
4.1. If you want to place a marker for a place, you have to pass longitude and latitude, not the full address. Then, how do you find the geocodes from an address? That's where Geokit comes in handy.
First put the following line early on in a controller where you will use the geocode.
include Geokit::Geocoders
Also add
to the model where you want to use the geocode caluculation. In my case, it would be playground model.
class Playground < ActiveRecord::Base
acts_as_mappable
end
There are many neat things you can do as you see in the example here.
In my case, the first is to find a location by user's IP address. You can use IpGeocoder method, but I found that it's not all that accurate.
@user_location = IpGeocoder.geocode(request.remote_ip)
if @user_location.success
lat = @user_location.lat
lng = @user_location.lng
end
If you have an address and want to find a geocode, then you can use MultiGeocoder.geocode. You can use any form of address: full address, city/state, or just zip. If you want to get a geocode for zip code 94085,
loc = MultiGeocoder.geocode('94085')
The geocode can be accessed by looking at loc.lat and loc.lng. The response to 94085 zip code looks like this.
Google geocoding. Address: 94085. Result:
94085
200
geocode
Sunnyvale, CA 94085, USA
USUSACASanta ClaraSunnyvale
94085
-122.0127067,37.3864411,0
If you have a geocode, you can also get an address by using GoogleGeocoder.reverse_geocode. When do the following,
addr = GoogleGeocoder.reverse_geocode [lat, lng]
you can access the address by looking at addr.street_address, addr.city, addr.state and addr.zip.
4.2. Once you have lat and lng, you can create a map. In a controller, initiate a map variable. Available options are explained in the rubyforge page. The following lines create a map, loads controls (like zoom level on the left side of a map), and centers the map at the lat, lng coordinate with a zoom level 13.
@map = GMap.new("map_div")
@map.control_init(:large_map => true, :map_type => true)
@map.center_zoom_init([lat,lng], 13)
4.3. After that, I find nearby playgrounds at the lat, lng coordinate in the same controller. This is a function of Geokit. It is finding all the playgrounds within 5 miles radius from lat, lng coordinate, ordered by average rating. Rating is function of acts_as_rated. Paginate will display only certain number of records per page specified by params[:page].
@playgrounds = Playground.find(:all, :origin => [lat, lng], :within => 5, :order => "rating_avg DESC").paginate :page => params[:page]
4.4. Once that's done, you have create markers and pass them to the @map variable. I didn't want put html codes in the controller (MVC violation!), but I couldn't really find a better way to do it. The content of infotxt will appear in the bubble when a user click on the marker.
@playgrounds.each do |p|
infotxt = "#{p.name}
#{p.address}
#{p.city}, #{p.state} #{p.zip.to_s}"
marker = GMarker.new([p.lat, p.lng], :title => p.name, :info_window => infotxt)
@map.overlay_init(marker)
end
4.5. Now, the map is finally ready to be displayed. First load GMap header information by adding the following line in the header field in app/views/layouts/application.html.erb.
<%= GMap.header %>
4.6. Then in a view where you want to place a map,
<%= @map.to_html %>
<%= @map.div(:width => 600, :height => 400) %>
Then viola! You should see the map in your view.
Mine has all the logic in the rails. However, if you put your logic in the javascript, then you should be able to do many cool things you see on Google Maps like showing driving direction, finding things nearby, etc. from the bubble window.
Some day I will move them to javascript side, but so far this way serves my purpose.
In the next post, I will talk about how to get new location from user and center the map to a new location using ruby javascript, rjs.
That seems like a good candidate to stuff into a helper:
def generate_info_text p
“#{p.name}
#{p.address}
#{p.city}, #{p.state} #{p.zip.to_s}”
end
then just have:
infotxt = generate_info_text p
in your controller.
I totally agree.
I am using rails 3. i have run the cmd ‘ruby script/plugin install svn://rubyforge.org/var/svn/ym4r/Plugins/GM/trunk/ym4r_gm‘.
But it is not installed and dint show any error. how do i install the plugin in rails 3. I need to display the google map based on ip address or location
Hey, it’s been a really long time since I touched the code….
great tips…thanks!!
Hi,
I need to trigger right click event on map and show pop up and also draw a circle based on radius. If you have any idea. Please help me.
Excellent – this has helped me a lot with Rails.
Pingback: mac
Pingback: Kumarakom Kerala
Pingback: Kumarakom
Pingback: SPFMoisturizers
Pingback: katadyn hiker pro
nice
Commonly I do not read post about sites, even so wish to state that this specific write-up pretty forced me to take a look at as well as practice it! Your creating flavor is amazed me personally. Appreciate it, pretty fantastic document.