Sunday, June 15, 2014

Location-aware Rails Model with Geokit Plugin

Beberapa minggu lalu saya diminta untuk membuat simulasi sederhana dari dispatching system untuk taksi menggunakan Ruby on Rails. Saya sempat membahas sekilas mengenai framework ini pada post saya sebelumnya. Salah satu fitur yang diminta dari dispatching system tersebut adalah fitur untuk mencari taksi terdekat dari lokasi calon penumpang taksi. Saya menggunakan Geokit plugin untuk Rails yang sangat mempermudah proses pencarian.

Berikut adalah langkah-langkahnya:
  1. Edit Gemfile pada Rails project, tambahkan baris berikut:
    gem 'geokit-rails'
  2. Buka Terminal pada direktori Rails project, kemudian jalankan perintah ini untuk menginstalasi geokit-rails plugin.
     $ bundle install
  3. Persiapkan database server yang compatible, saya menggunakan MySQL pada post ini. Berikut adalah snippet config/database.yml yang digunakan.
    default: &default
      adapter: mysql2
      encoding: utf8
      pool: 25
      timeout: 5000
      username: root
      password:
      socket: /tmp/mysql.sock
    
    development:
      <<: *default
      database: booking_dev
    
    # Warning: The database defined as "test" will be erased and
    # re-generated from your development database when you run "rake".
    # Do not set this db to the same as development or production.
    test:
      <<: *default
      database: booking_test
    
    production:
      <<: *default
      database: booking
    
  4. Buat model Driver sebagai representasi sopir taksi. Sopir taksi ini juga memiliki 2 atribut lokasi yaitu longitude dan latitude.
     $ rails generate scaffold Driver name:string phone:string latitude:decimal{10.6} longitude:decimal{10.6}
  5. Jalankan script migration untuk membuat tabel drivers.
     $ bin/rake db:migrate RAILS_ENV=development
  6. Persiapkan seed data menggunakan rake task. Buat file db/seeds.rb untuk mengisi tabel drivers. Misalnya seperti ini:
    Driver.delete_all
    Driver.create!(name: 'Adam Ashton', phone: '+62811234567', latitude: (rand -90.000000..90.000000).round(6), longitude: (rand -180.000000..180.000000).round(6))
    Driver.create!(name: 'Brian Borrowick', phone: '+62812234644', latitude: (rand -90.000000..90.000000).round(6), longitude: (rand -180.000000..180.000000).round(6))
    Driver.create!(name: 'Charlie Chuckles', phone: '+62813234698', latitude: (rand -90.000000..90.000000).round(6), longitude: (rand -180.000000..180.000000).round(6))
    Driver.create!(name: 'Damian Delaware', phone: '+62814234526', latitude: (rand -90.000000..90.000000).round(6), longitude: (rand -180.000000..180.000000).round(6))
    Driver.create!(name: 'Edward Ernst', phone: '+62815349347', latitude: (rand -90.000000..90.000000).round(6), longitude: (rand -180.000000..180.000000).round(6))
    Driver.create!(name: 'Finn Flannigan', phone: '+62816287667', latitude: (rand -90.000000..90.000000).round(6), longitude: (rand -180.000000..180.000000).round(6))
    Driver.create!(name: 'Gregory Georgetown', phone: '+62817255667', latitude: (rand -90.000000..90.000000).round(6), longitude: (rand -180.000000..180.000000).round(6))
    Driver.create!(name: 'Hendrick Henderson', phone: '+62818200967', latitude: (rand -90.000000..90.000000).round(6), longitude: (rand -180.000000..180.000000).round(6))
    Driver.create!(name: 'Ian Impala', phone: '+62819235467', latitude: (rand -90.000000..90.000000).round(6), longitude: (rand -180.000000..180.000000).round(6))
    Driver.create!(name: 'Jeremy Jefferson', phone: '+62810234887', latitude: (rand -90.000000..90.000000).round(6), longitude: (rand -180.000000..180.000000).round(6))
    
  7. Jalankan rake task untuk menghasilkan seed data pada poin sebelumnya.
     $ bin/rake db:seed
  8. Validasi di MySQL client bahwa perintah rake sebelumnya berjalan dan data berhasil di-generate.
    Tabel drivers via Sequel Pro app
  9. Aktifkan plugin geokit-rails pada model Driver dengan cara menambahkan fungsi acts_as_mappable pada file app/models/driver.rb seperti berikut:
    class Driver < ActiveRecord::Base
      acts_as_mappable default_units: :kms, default_formula: :sphere, distance_field_name: :distance, lat_column_name: :latitude, lng_column_name: :longitude
    end
    
  10. Uji coba dengan menjalankan perintah berikut pada rails console.
     $ rails console
    irb(main):001:0> jeremy = Driver.find(10)
    irb(main):002:0> distance = 10000
    irb(main):003:0> Driver.within(distance, :origin => jeremy).first
  11. Perintah tersebut seharusnya akan mengembalikan sopir terdekat dari Jeremy Jefferson dalam radius 10.000 km :) Jika perintah tersebut tidak mengembalikan apa-apa tapi tidak error, berarti seed datanya harus kita persempit lagi lokasinya, hehe
Selamat mencoba ya! :D

No comments:

Post a Comment