Category Archives: RubyOnRails
setup a geospatial-restful API and document it for others
UPDATE: I’ve had some criticism of the geo_scaffold code… which was really meant for my personal use. I’m tuning it up for a public release… check back in a few weeks.
Introduction
Following on from my last post where we created a mapping app using geo_scaffold I am going to show how to use cURL to play around with the RESTful location API that geoscaffold has generated for us. Geoscaffold has built us a working RESTful API that can be used with a bit tweaking. So all resources are accessable via a URL and HTTP verbs (GET/PUT/POST/DELETE). The basic API can be accessed via KML and GeoRSS flavor of XML and can simply be access by adding “.xml”, “.kml” or “.georss” to the end of your URL.
GET
curl http://localhost:3000/hotspots/1.kml
Authentication
We can add simple HTTP authentication very easily.
You will need a username and password for accessing the API. Login/pwd can be requested. Authentication is implemented as a basic HTTP authentication. in your controller
class HotspotsController < ApplicationController
before_filter :authenticate
...
protected
def authenticate
authenticate_or_request_with_http_basic do |username, password|
username == "shoaib" && password == "secret"
end
end
end
lets try it out:
curl -u shoaib:secret http://localhost:3000/hotspots/1.kml
WRITE
In order to write to a resource we use the POST http method.
curl -u shoaib:secret -X POST -d "hotspot[name]=Merriot-San-Francisco& \
hotspot[description]=Where20+conference+not2b+missed&lat=37.602561& \
lng=-122.37096" http://localhost:3000/hotspots.xml
UPDATE
Updating the database requires the PUT method.
curl -u shoaib:secret -X PUT -d "hotspot[name]=My+current+location& \
hotspot[description]=Where20+conference+is+in+progress& \
lat=37.602561&lng=-122.37096" http://localhost:3000/hotspots/1.xml
DELETE
Delete the database requires the DELETE method.
curl -u shoaib:secret -X DELETE http://localhost:3000/hotspots/1.xml
how to setup a new edge rails project with a geostack
Edgerails: If I want to run edgerails with all my geostack development tools it can get quite long winded. So I have tried to compile this post hoping to it will inspire me to create a script to automate it … something like railify which I forked from Nicolás Sanguinetti with that very intent. Also given that rails and several other projects are moving to git I decided to try the git submodules for tracking remote git repos.
To get edge rails working as a git submodule checkout this excellent post. Except I am going to grab edgerails from my local fork to save me time and money.
$ rails geostack -d postgresql
$ cd geostack/
$ cat /c/apps/Rails/templates/dot-gitignore > .gitignore
$ touch log/.gitignore
$ git init
$ git status
$ git add .
$ git commit -m "Initial commit"
$ cd /c/apps/Rails/_rails/
$ git pull origin
$ cd /c/NetBeansProjects/geostack/
$ git submodule add /c/apps/Rails/_rails/ vendor/rails
Initialized empty Git repository in c:/NetBeansProjects/geostack/vendor/rails/.git/
lets see what we did
$ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD
#
# new file: .gitmodules
# new file: vendor/rails
all good to commit and initialize the submodules
$ git commit -m "Use git submodules to track HEAD of local _rails repository."
Created commit 327f3b8: Use git submodules to track HEAD of local _rails repository.
2 files changed, 4 insertions(+), 0 deletions(-)
create mode 100644 .gitmodules
create mode 160000 vendor/rails
$ git submodule init
Submodule 'vendor/rails' (c:/apps/Rails/_rails/.git) registered for path 'vendor/rails'
git submodule update
Lets now get the plugins. Starting with spatial_adapter2 which I forked to add geo_scaffold (discussed later)
$ git submodule add git@github.com:sabman/spatial_adapter2.git vendor/plugins/spatial_adapter2
$ git commit -m "Import of spatial_adapter2 from github"
or if u don’t care about tracking it just do:
$ ruby script/plugin install git://github.com/sabman/spatial_adapter2.git
then ym4r_gm again 2 options:
$ git submodule add git://github.com/bitbckt/ym4r-gm.git vendor/plugins/ym4r_gm
$ git commit -m "ym4r_gm added"
or
$ ruby script/plugin install git://github.com/bitbckt/ym4r-gm.git
next the good old geokit
$ ruby script/plugin install git://github.com/ptb/geokit.git
finally seeing as I’m too slack to test unless its TDD we get rspec and rspec_on_rails.
First I update my local git fork of rspec and rspec-rails so we don’t have to keep cloning the huge remote repo
cd /c/apps/Rails/my_plugins/rspec
git pull
cd /c/apps/Rails/my_plugins/rspec-rails
git pull
git add .
git commit -m "update"
#Add git submodules for the local projects
git submodule add /c/apps/Rails/my_plugins/rspec vendor/plugins/rspec
git submodule add /c/apps/Rails/my_plugins/rspec-rails vendor/plugins/rpec_on_rails
git status
git diff --cached
git commit -m "Import the RSpec & Rspec-rails plugins' current HEAD as a submodule."
# and finalize
$ git add .
$ git commit -m "added required plugins"
next create a PostGIS database and setup database config
createdb -T template_postgis geostack_development -U postgres
development:
adapter: postgresql
encoding: UTF8
database: geostack_development
username: postgres
password: secret
test:
adapter: postgresql
encoding: UTF8
database: geostack_test
username: postgres
password: secret
production:
adapter: postgresql
encoding: UTF8
database: geostack_production
username: geostack
password:
… and my ugly hack to ensure our test database rake task create the correct database we are going to modify the default databases.rake file from rails. don’t look
$ find ./vendor/rails/ -type f -iname databases.rake | xargs -i cp {} ./lib/tasks/databases.rake.orig
$ sed 's/^.*`createdb .* -U "#{.*}"/& -T template_postgis /' ./lib/tasks/databases.rake.orig > ./lib/tasks/databases.rake
rm ./lib/tasks/databases.rake.orig
ok all done… geo_scaffold in action:
$ ruby script/generate geo_scaffold Hotspot name:string description:text location:point
mime_types Mime::Type.register "application/vnd.google-earth.kml+xml", :kml
mime_types Mime::Type.register "application/rss+xml", :georss
exists app/models/
exists app/controllers/
exists app/helpers/
create app/views/hotspots
exists app/views/layouts/
exists test/functional/
exists test/unit/
create app/views/hotspots/index.html.erb
create app/views/hotspots/show.html.erb
create app/views/hotspots/new.html.erb
create app/views/hotspots/edit.html.erb
create app/views/hotspots/index.kml.builder
create app/views/hotspots/index.georss.builder
create app/views/hotspots/show.kml.builder
create app/views/hotspots/show.georss.builder
create app/views/layouts/hotspots.html.erb
create public/stylesheets/geo_scaffold.css
create public/images/google_earth16x16.gif
create public/images/google_earth32x32.gif
create public/images/feed-icon16x16.png
create public/images/feed-icon32x32.png
create public/images/kml_icon16x16.png
create public/images/feed-icon16x16.gif
create public/images/bullet.gif
create public/images/header_backdrop.png
create public/images/Globe2.png
create public/javascripts/geo_scaffold.js
create app/controllers/hotspots_controller.rb
create app/helpers/hotspots_helper.rb
route map.resources :hotspots
dependency geo_model
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/hotspot.rb
create test/unit/hotspot_test.rb
create test/fixtures/hotspots.yml
create db/migrate
create db/migrate/20080429142617_create_hotspots.rb
exists db/migrate
create db/migrate/20080429142618_add_index_to_hotspots.rb
Run migrations and go!
$ rake db:migrate
$ mongrel_rails start
And here is the result tada!

Google Earth on Rails
There is a little post on getting Google Earth and Rails apps talking to each other at: GE-Rails. There is even a hint on using merb instead or Rails
Slides for RailsConf Europe 2007
Rails GIS Hack Slides are now available for download at rails.nomad-labs. Also on SlideShare Enjoy!
busy in Berlin!
Its been a great 2-3 days hangin’ with some of my hero’s from the Ruby/Rails world. On Friday we had dinner with Dr Nic and today I learnt about the finer points of RSpec with Dr Nic and Geoffrey of Peepcode fame at the Sankt Oberholz.
Geoffrey also made the fatal mistake of showing Aleks his iPhone who completely ignored his celebrity status and spent the rest of the afternoon playing with his phone.
Kashif in the spirit of good hostmanship has put up a map on the nomad-labs rails blog especially setup for RailsConf Europe 2007. So if you are here and want to know about where all the hip people hang do check it out!
Kashif has also ended up with a bottle of cognac thanks to our new Romanian friend :)
Geospatial @ RailsConf Europe 2007
Some great news for those interested in the convergence between Ruby/Rails and Geospatial applications. Kashif and I will be giving a tutorial at RailsConf in Berlin. There is going to be 3 hr tutorial titled Rails GIS Hacks, where we will be going through some pretty nifty stuff such as RESTful geospatial applications development. Hope to see you there!
Ruby/GDAL How to open a dataset (1)
I’ll try to post some code snippets on the use of GDAL Ruby bindings. In case you don’t already know there is a bleeding edge gentoo overlay maintained by Kashif at gentoo geo-overlay
I am working on a howto for using that as well to build a gentoo box with some of the latest Open Source Geo-tools.
require 'gdal/gdal'
require 'gdal/gdalconst'
include Gdal
file = "./rasterdata.tif"
begin
@dataset = Gdal::Gdal.open(file, Gdalconst::GA_READONLY)
rescue RuntimeError
$stderr.print "Gdal failed to open #{file}.\n"
exit
end
Pakistan Wetlands and Ramsar listed sites

Wetlands are regarded by nature conservationist as unique ecosystems. They often exhibit delicately balanced environmental conditions and support a wide range of exotic plant and animal species. Wetlands are also often protected by various environmental laws and conventions. Last year when I was visiting Pakistan I learned about the Pakistan Wetlands Project that is under way. The aim of the project is to build capacity for improved wetlands management at the Federal, Provincial and Local government level, as well as the private sector in Pakistan. I thought it would be nice to be able to see all 19 wetlands in Pakistan that are listed under the Ramsar convention on GoogleMaps. This site was built using RubyonRails + GeoRuby. http://pakistan-wetlands.dyndns.org/. Many thanks to Guilhem for his help during trouble shooting.
taking GDAL/OGR ruby bindings for a spin
Since i have volunteered to write the gdal ruby-binding test cases i thought it would be a good time to try out some of the ogr ruby-bindings. Charlie Savage has done a lot of work on the gdal SWIG ruby biniding and already written the test suite for OGR. Thanks to his excellent instructions on how to get started with writing the gdal-ruby test suit i was able to to easily convert Ari Jolma’s dumpall.pl to a ruby script to dump the contents of ogr (Vector) datastore.
require 'gdal/ogr'
@global_extent = Array.new#(4, 0.0)
def dump_geom(geom, v)
print " Geometry type: ", geom.get_geometry_type, "\n"
print " Geometry name: ", geom.get_geometry_name, "\n"
extent = geom.get_envelope
print " BBox: ", extent[0], " ", extent[2], " ", extent[1], " ", extent[3], "\n"
for i in [0, 2]
if (@global_extent[i].nil?) or @global_extent[i] > extent[i]
@global_extent[i] = extent[i]
end
end
for i in [1, 3]
if (@global_extent[i].nil?) or @global_extent[i] < extent[i]
@global_extent[i] = extent[i]
end
end
if (geom.get_geometry_count > 0)
print "Geom Count = ", geom.get_geometry_count, "\n"
geom.get_geometry_count.times do |i|
dump_geom(geom.get_geometry_ref(i),v)
end
else
if(!v)
print "PointCount: ", geom.get_point_count,"\n"
geom.get_point_count.time do |i|
x = geom.get_x(i)
y = geom.get_y(i)
z = geom.get_x(i)
print " ", x, " ", y, " ", z, "\n";
end
end
end
end
def dump_feature_data(feature, layer)
feature_defn = layer.get_layer_defn
print "Feature ID: ", feature.get_fid, "\n"
feature_defn.get_field_count.times do |i|
print "Field ", i+1, "\n"
field_defn = feature_defn.get_field_defn(i)
print " Field name: ",field_defn.get_name_ref,"\n"
type = field_defn.get_type
print " Field type: ", field_defn.get_field_type_name(type)," type\n"
field = feature.get_field_as_string(i);
print " Field value: ", field,"\n"
end
end
def dump_layer(layer)
layer.reset_reading
layer.get_feature_count.times do |i|
feature = layer.get_feature(i)
dump_feature_data(feature, layer)
geom = feature.get_geometry_ref()
do_not_show_vertices = 1
if not geom.nil?
dump_geom(geom, do_not_show_vertices)
elsif geom.nil?
print "*** expected geometry but got nill\n"
end
end
end
if ARGV.length < 1
print "Usage: #$0", "
\n"
exit
else
filename = ARGV[0]
end
# driver = Gdal::Ogr.get_driver_by_name('ESRI Shapefile')
# open file as a OGR dataset
dataset = Gdal::Ogr.open(filename)
print "Looking at ", filename + " ...\n"
# get the number of layers
layer_num = dataset.get_layer_count
layer_num.times do |i|
layer = dataset.get_layer(i)
print " looking at layer num: ", i+1 , "\n",
" Name: "+layer.get_name + ", Features: "+ layer.get_feature_count.to_s + "\n"
dump_layer(layer)
end