Sabtu, 26 Oktober 2013

Geocode di Rails


Pada sesi sebelumnya kita telah mempelajari bagaimana cara instalasi Google Maps v3 pada aplikasi Rails yang kita buat dan juga field autocomplete dengan menggunakan jQuery Flexbox

Sesi kali ini akan membahas kasus lain dari google maps dan pointing lokasi berdasarkan input nama daerah atau lebih dikenal dengan nama geocode. Sebagai contoh di sini provinsi dan nama kota berasal dari Indonesia. 
Misalkan kita input Jawa Barat sebagai provinsi dan Bandung sebagai nama kotanya, maka google maps akan pointing ke kota Bandung provinsi Jawa Barat.

Pertama kita buat model user yang berisi nama serta informasi lokasinya


rails g model user name:string city_name:string state_name:string country_name:string


Untuk memuat data lokasi sebagai opsi, buat juga model city dan statenya



rails g model city name:string state_id:integer

rails g model state name:string


dan rake db:migrate

Setelah itu buat relasi antara city dan state 
app/models/city.rb

class City > ActiveRecord::Base
 belongs_to :state
end

app/models/state.rb

class State > ActiveRecord::Base
 has_many :cities
end

Relasi antara state dan city akan memudahkan untuk populate nama kota berdasarkan nama provinsinya masing-masing. Untuk mempermudah dalam membuat data state dan city, tambahkan di app/db/seeds.rb


State.create(
 [
  {:name => "West Java"},
  {:name => "Central Java"},
  {:name => "East Java"}
 ]
)

#City
country = Country.find_by_name("Indonesia")
west_java = State.find_by_name("West Java")
central_java = State.find_by_name("Central Java")
east_java = State.find_by_name("East Java")
City.create(
 [
  {:name => "Bandung", :state_id => "#{west_java.id}"},
  {:name => "Bogor", :state_id => "#{west_java.id}"},
  {:name => "Sukabumi", :state_id => "#{west_java.id}"},
  {:name => "Semarang", :state_id => "#{central_java.id}"},
  {:name => "Kudus", :state_id => "#{central_java.id}"},
  {:name => "Demak", :state_id => "#{central_java.id}"},
  {:name => "Surabaya", :state_id => "#{east_java.id}"},
  {:name => "Lamongan", :state_id => "#{east_java.id}"},
  {:name => "Tulungagung", :state_id => "#{east_java.id}"}
 ]
)
Lalu jalankan di console rake db:seed 


Setelah langkah-langkah di atas baru kita bisa mulai membuat bagian view nya. Misal kita akan membuat user baru beserta data lokasinya. Buat method di app/controllers/users_controller.rb untuk halaman create user.
def new
  @user = User.new
end

private 

def prepare_state
 @states = State.all.map{|x|x.name}.unshift(['Please select', ''])
end
Lalu buat app/views/users/new.html.erb yang berisi form untuk create user : 
<script type="text/javascript"
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAVdlyqpDfn1sXmYcY9WJS4cfU0jnkIWao&sensor=false">
    </script>
<script type="text/javascript">
      function initialize() {
        var mapOptions = {
          center: new google.maps.LatLng(-7.2099,110.606918),
          zoom: 3,
          mapTypeId: google.maps.MapTypeId.ROADMAP
        };
        var map = new google.maps.Map(document.getElementById("map-canvas"),
            mapOptions);
      }
      google.maps.event.addDomListener(window, 'load', initialize);
  
  $(document).ready(function(){
    initialize();
  })
</script>

<%= form_for @user do |form| %>
    <%= form.label :name %>&nbsp;<%= form.text_field :name %>
     <br />
      <div class="locations">
      <%= form.label :state_name, "Provinsi" %>&nbsp;<%= form.select :state_name, options_for_select(@states) %>
      <br />
       <%= form.label :city_name, "Kota" %>&nbsp;<div id="city_name"></div>
       <%= form.hidden_field :city_name %>
     </div>
     <br />
   <div id="map-canvas" style="width:300px;height:200px"/>
<%end%>
View di atas masih berupa form create user dan google maps saja. 



Untuk pointing lokasi di map berdasarkan input diperlukan beberapa fungsi javascript untuk trigger ketika dropdown provinsi dipilih. Input nama kota di atas juga menggunakan jquery flexbox untuk autocomplete  yang telah dibahas pada sesi sebelumnya.

Fungsi trigger untuk pointing lokasi di map berdasarkan input provinsi diambil contoh seperti ini
<script type="text/javascript">
$(document).ready(function(){
   $("#user_state_name").on("change", function(){
     set_map($(this).val());
  });


      function set_map(city,state,country){
        var mapOptions = {
          center: new google.maps.LatLng(-7.2099,110.606918),
          zoom: 7,
          mapTypeId: google.maps.MapTypeId.ROADMAP
        };
        country = "Indonesia";
        var map = new google.maps.Map(document.getElementById("map-canvas"),
        mapOptions);

        if(city == ''){
          address = state + ',' + "Indonesia"
        }else{
          address = city + ',' + state + ',' + "Indonesia"
        }

        var geocoder = new google.maps.Geocoder();

        geocoder.geocode({
          'address':address
        },

        function(result, status){
          if (status == google.maps.GeocoderStatus.OK){
            map.setCenter(result[0].geometry.location);

            var marker = new google.maps.Marker({
              map: map,
              position: result[0].geometry.location
            });
          }else{
            alert("Geocode was not successful for the following reason: " + status);
          }
        });
        return false;
      }
</script>
Selain pointing lokasi, ketika dropdown provinsi dipilih juga akan populate nama kota di bawah provinsi tersebut. Agar data provinsi dan kota sesuai maka diperlukan relasi antara keduanya serta AJAX untuk merequest perubahan data city berdasarkan state yang dipilih. 

Pertama kita tambahkan buat method populate_cities di app/controllers/users_controller.rb. Method tersebut hanya untuk load halaman partial untuk meload kembali form user tapi dengan catatan field city yang sudah berisi data city sesuai state yang dipilih.
def populate_cities
  render :layout => false
end

Setelah itu buat fungsi javascript untuk populate_cities ketika dropdown provinsi dipilih
$(document).ready(function(){
   $("#user_state_name").on("change", function(){
    populate_cities();
     set_map($(this).val());

   function populate_cities(){
      var base_address = $(".locations");
      var controller = "<%= populate_cities_users_path %>";
      $.ajax({
        type: "GET",
        url: escape(controller),
        data: {"state_name" : $('#user_state_name').val()},
        dataType:"html",
        beforeSend:function(){
          $('#city_name_input').attr('disabled', 'disabled').css('background-color', '#E6E6E6');
        },
        success:function(data){
          jQuery(".locations").html(data);
        }
      })
    }
  });
Ketika fungsi tersebut di-execute maka akan merender halaman partial tanpa harus meload ulang satu halaman untuk populate data city. Buat halaman partial sesuai nama method populate_cities (app/views/users/populate_cities.erb). Pada halaman partial tersebut juga disertakan fungsi javascript untuk autocomplete nama kotanya. 


<script type="text/javascript">
  function cities_flexbox(){
    var query = "<%= @city_name %>";
    jQuery("#city_name").flexbox('<%= autocomplete_city_users_path %>',{
      customParameters: {q: query, state_name: $('#user_state_name').val()},
      method: 'post',
      watermark: query,
      showArrow: false,
      inputClass: 'inpu',
      minChars: 2,
      width:200,
      queryDelay: 300,
      paging:true,
      highlightMatches:true,
      containerClass:'ffbContainer',
      onSelect: function(){
        $("#user_city_name").attr('value', this.getAttribute('hiddenValue'));
        set_map($("#user_city_name").val(),$("#user_state_name").val(),'Indonesia');
      }
    });
  }

  $(function(){
    cities_flexbox();
  });
</script>
  <label>Provinsi :</label>&nbsp;
  <%= select_tag 'user[state_name]', options_for_select(@states, params[:state_name]) %>
  <br />
  <label>Kota :</label>
<div id="city_name"></div>
<%= hidden_field_tag "user[city_name]" %>
Fungsi cities_flexbox()di atas merupakan fungsi javascript untuk meload field input autocomplete. Ketika field input autocomplete diisi nama city maka akan muncul datanya sesuai dengan keywordnya dan ketika dipilih maka google maps akan pointing lokasi berdasarkan state dan city nya. 

Berikut ini adalah hasil dari geocode yang sudah terintegrasi dengan rails :









Selamat mencoba dan happy coding :)


Kamis, 24 Oktober 2013

Field Autocomplete Menggunakan jQuery Flexbox di Ruby on Rails

Field autocomplete memudahkan kita dalam memilih opsi dari data sangat banyak. Dengan field autocomplete kita tidak perlu direpotkan untuk scroll field dropdown apabila data yang ditampilkan sangat banyak. Dan data yang ditampilkan hanyalah data yang kriterianya sesuai dengan kata kunci (keyword). 

Pada sesi kali ini akan dibahas mengenai instalasi jQuery Flexbox yang digunakan untuk field autocomplete dan integrasi dengan Rails. 
Sebagai contoh adalah field autocomplete untuk mencari nama User. 

Persiapan

Pertama download terlebih dahulu versi terbaru dari jQuery Flexbox di sini.
Setelah itu extract isi folder zip dan copy file jquery.flexbox.min.js ke dalam folder aplikasi rails app/assets/javascripts/ dan file jquery.flexbox.css ke dalam folder app/assets/stylesheets/. Jangan lupa untuk tag masing-masing assets javascript dan stylesheet tersebut di layout, misalkan layout yang dipakai adalah app/views/layouts/application.html.erb :
<!DOCTYPE html>
<html>
<head>
  <title>Autocomplete</title>
  <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
  <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
  <%= stylesheet_link_tag    "application", :media => "all" %>
  <%= javascript_include_tag "application" %>

  <%= stylesheet_link_tag "jquery.flexbox" %>
  <%= javascript_include_tag "jquery.flexbox.min" %>
  
  <%= csrf_meta_tags %>
</head>
<body>

<%= yield %>

</body>
</html>

Implementasi di Rails 

Setelah itu buat model User  yang berisi column first_name (strings) dan last_name (strings) dengan generate script di bawah ini di terminal :


rails g model user first_name:string last_name:string

dan rake db:migrate

Lalu buat beberapa user via rails console, misalkan :


User.create!(
 [
  {:first_name => "John", :last_name => "Doe"},
  {:first_name => "John", :last_name => "Smith"},
  {:first_name => "John", :last_name => "Lennon"}
 ]
)



Untuk menampilkan fullname dari user , buat method di app/models/user.rb seperti ini
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name

  def full_name
    self.first_name + " " + self.last_name
  end

end

Buat fungsi autocomplete nya di controller, misalkan di users_controller.erb
def autocomplete
  result = []
  users = User.find(:all, :conditions => ["users.first_name LIKE ? OR users.last_name LIKE ?", "%"+params[:q]+"%", "%"+params[:q]+"%"])
  users.each{|x|
    result << {'id' => "#{x.full_name}", 'name' => "#{x.name.to_s}" } unless x.name.blank? }
  render :json => {"results" => result, "total" => (users ? users.length : 0) }
end
Jangan lupa daftarkan fungsi tersebut di config/routes.rb dengan method POST
resource :users do
  collection do
    post 'autocomplete'
  end
end

Setelah itu kita implementasikan fungsi javascript pada bagian viewnya, misalkan di app/views/users/index.html.erb
<style type="text/css">
.inpu
  {
    background: #fff;
    width: 440px;
    border: 2px solid #666;
    border-radius: 4px;
    padding-top: 10px;
    padding-bottom: 10px;
    padding-left: 8px;
    color: #aaa;
    font-family: Arial, Helvetica, sans-serif;
  }
  </style>

<script type="text/javascript">
function users_flexbox(){
    var query = "<%= @user_name %>";
    jQuery("#name_input").flexbox('<%= autocomplete_users_path %>',{
      method: 'post',
      watermark: query,
      showArrow: false,
      inputClass: 'inpu',
      minChars: 2,
      width:200,
      queryDelay: 300,
      paging:true,
      highlightMatches:true,
      containerClass:'ffbContainer',
      onSelect: function(){
        alert(this.getAttribute('hiddenValue'));
      }
    });
  }

  $(document).ready(function(){
   users_flexbox();
  });
</script>

<label>Name :</label>
<div id="name_input"></div>
Fungsi javascript users_flexbox() di atas merupakan fungsi javascript untuk load field input yang sudah diintegrasikan dengan jQuery Flexbox. Dan dari fungsi javascript di atas juga bisa disesuaikan dengan kebutuhan aplikasi yang kita buat. Untuk dokumentasi jQuery flexbox sendiri bisa dilihat di sini.

Setelah langkah-langkah di atas selesai diimplementasikan, kita bisa mencoba input keyword dan bisa langsung melihat hasilnya.




Selamat mencoba dan happy coding :)

Rabu, 23 Oktober 2013

Instalasi Google Maps v3 pada Rails

Google Maps API memudahkan kita dalam memuat google maps pada aplikasi web yang kita buat.
Berikut ini adalah langkah-langkah instalasi google maps pada Ruby on Rails.


Get Google API Key
Langkah berikut ini menjelaskan bagaimana mendapatkan google maps API key yang akan kita gunakan pada aplikasi kita.
Pertama, pastikan kita memiliki akun google.

1. Masuk ke halaman console API google dan login dengan menggunakan account google atau gmail. 
2. Klik link Services pada menu di sebelah kanan. 



3. Aktivasi servis Google Maps API v3 dengan klik tombol switch pada bagian kanan, lalu ikuti langkah selanjutnya dengan klik checkbox agree


4. Klik link API Access, dan API key untuk google maps telah tersedia di halaman ini. 


Instalasi dengan Ruby on Rails
Misalkan pada aplikasi yang kita buat akan menampilkan profile user dan menampilkan lokasi di map berdasarkan alamat usernya. 
Pertama buat model user yang berisi nama:string, city:string dan state:string


rails g model user name:string city:string state:string


Lalu buat user di console, misalkan


User.create!(
 [
  {:name => "John Doe", :city => "Washington", :state => "DC"}
 ]
)

Lalu buat halaman show untuk melihat detail dari profile user, buat misalkan di app/views/users/show.html.erb. Lalu masukkan API key di atas ke dalam code javascript di bawah ini. 

Contoh :
 <style type="text/css">
      html { height: 100% }
      body { height: 100%; margin: 0; padding: 0 }
      #map-canvas { height: 100% }
    </style>
    <script type="text/javascript"
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAVdlyqpDfn1sXmYcY9WJS4cfU0jnkIWao&sensor=false">
    </script>
    <script type="text/javascript">
   function set_map(state, city){
    var mapOptions = {
      center: new google.maps.LatLng(25.687944,-100.309403),
      zoom: 8,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    var map = new google.maps.Map(document.getElementById("map-canvas"),
    mapOptions);

    if(state == ""){
      address = city;
    }else{
      address = state + ',' + city;
    }

    var geocoder = new google.maps.Geocoder();

    geocoder.geocode({
      'address':address
    },

    function(result, status){
      if (status == google.maps.GeocoderStatus.OK){
        map.setCenter(result[0].geometry.location);

        var marker = new google.maps.Marker({
          map: map,
          position: result[0].geometry.location
        });
      }else{
        alert("Geocode was not successful for the following reason: " + status);
      }
    });
    return false;
  }

   $(document).ready(function(){
     set_map('<%= @user.state %>', '<%= @user.city %>');
   })
    </script>
    

<label>Name : </label>&nbsp;<%= @user.name %>
<br />
<label>Location :</label>
<br />
<br />
<div id="map-canvas" style="width:300px;height:200px"/>
Fungsi javascript set_map(state, city) di atas merupakan fungsi untuk menampilkan map dari lokasi setiap user dengan mendefinisikan variable city dan state sebagai city dan state milik user. Sehingga map yang ditampilkan juga dinamis, tergantung data dari usernya.  
Untuk inisialisasi map juga bisa disesuaikan tergantung lokasi mana yang akan ditampilkan dengan mengubah script di atas dengan menginput latitude dan longitude nya saja.
center: new google.maps.LatLng(latitude,longitude)
Berikut ini adalah contoh dari halaman profile user berdasarkan input data user di atas




Contoh kasus sederhana lainnya dari google maps dan Ruby on Rails adalah pointing lokasi berdasarkan input kota atau provinsi/region menggunakan AJAX  yang akan dibahas pada sesi selanjutnya.


Selamat mencoba dan happy coding :)

Sumber : 
https://developers.google.com/maps/documentation/javascript/tutorial


Membuat Pretty URL Menggunakan FriendlyId


FriendlyId merupakan gem untuk membuat url menjadi lebih bersahabat. Misal pada aplikasi kita terdapat model user, ketika kita ingin melihat detail dari user tertentu biasanya url menunjukan /users/id_user. Akan lebih bermakna jika url tersebut menjadi /users/nama_user, nah agar FriendlyId merupakan gem yang bisa membantu kita menjadikan url tidak menggunakan id tapi slug.

Pada kesempatan ini akan dijelaskan mengenai cara menggunakan FriendlyId pada aplikasi ruby on rails, berikut langkah-langkahnya: 

- Tambahkan pada Gemfile

gem "friendly_id"

- Kemudian pada console jalankan  

gem "friendly_id"

- Buat User menggunakan scaffold

rails generate scaffold user name:string slug:string

- Edit file migration untuk create user, lalu pada file migration tersebut tambahkan script berikut

add_index :users, :slug, unique: true

- Kemudian pada console jalankan 

rake db:migrate

- Edit model user sehingga menjadi seperti berikut

class User < ActiveRecord::Base
  extend FriendlyId
  friendly_id :name, use: :slugged
end

- Buat user pada console

User.create! name: "John Smith"

- Kemudian jalankan server

rails server

- Kemudian jalankan browser lalu ketikan url berikut

http://localhost:3000/users/john-smith


Selamat mencoba dan Happy Coding :)