Nhúng google map vào ứng dụng rails với gem Geocoder

Hôm nay mình sẽ chuyển qua Rails và trình bày một cách đơn giản để sử dụng bản đồ trong ứng dụng rails với gem Geocoder. Về google map api mọi người có thể tham khảo bài viết Google map API .

Get Google API key

Để sử dụng được Google Maps API, chúng ta cần phải đăng ký app project trên Google API Console và get API key để dùng. Mọi người có thể get key đơn giản bằng cách click vào nút get a key qua link sau: Quick start to get API key hoặc có thể đăng ký và quản lý key cho project qua Googel API Console Sau khi get key xong chúng ta cần thêm đoạn script để dùng API của Google như sau:

<script src="//maps.google.com/maps/api/js?v=3.27&key=AIzaSyDEHpTjzc2CyFPY_m-_QCBWDI25w2pbnYM"></script>

Note: ở đây mình chỉ định luôn là Google map api version 3.27. đoạn script này chúng ta có thể thêm ngay trong phần view cần dùng.

Geocoder

Ok vậy là bước chuẩn bị key đã xong. Trước hết mình sẽ giới thiệu qua gem geocoder và tại sao mình dùng nó mà không phải 1 gem khác như gmaps4rails. Trước hết Geocoder là một giải pháp mã hóa địa lý trong Ruby. Nó có một vài tính năng cụ thể như sau:

  1. Chuyển đổi địa điểm thành tọa độ địa lý và ngược lại
  2. Tìm địa điểm gần vị trí cho trước
  3. Chuyển đổi địa chỉ IP thành vị trí

Trước đó khi chuẩn bị làm task này mình nghĩ đến gem gmaps4rails nhưng rồi đọc tìm hiểu thì thấy cần thêm cả thư viện js ngoài như underscore để custom map hay việc tạo và generate JSON để tạo map khá phức tạp. Trong khi cái mình thực sự cần là latitude (vĩ độ)longitude (kinh độ). Rồi tìm hiểu thì mình thấy geocoder làm đơn giản và khá mạnh nếu mình khai thác thêm như mấy chức năng cơ bản mình nêu trên. À ngồi vọc còn thấy ngoài author chính là Alexreisner thì còn có chị Phạm Thu Trang là contributor (xếp thứ 2 và có quyền merge pull request 😄).

Instruction
  1. Database Migration Mình xin bỏ qua bước cài đặt gem. Chúng ta thêm 2 trường latitudelongitude vào trong bảng mà chúng ta dùng để lưu vị trí. Cụ thể ở đây mình lưu ở bảng Address. Note: lưu ý chính tả nhé. khi tạo database migration team-mate mình thuận miệng và tạo là longtitude.
  2. Modify model: Migrate xong thì chúng ta thêm đôi dòng như sau:
    geocoded_by :address
    after_validation :geocode, if: :address_changed?
    
    ở đây mình sẽ dựa vào trường address để lấy vĩ độ và kinh độ cho địa điểm. và after_validation là để generate lại kinh độ và vĩ độ khi address thay đổi. Cũng không quá khó hiểu lắm
  3. Generate latitude and longitude Cái này cũng khá giống với việc re-index trong elasticsearch đó là chúng ta chạy lệnh để generate vĩ độ và kinh độ cho địa chỉ có sẵn trong database:
    rake geocode:all CLASS=Address SLEEP=0.25 BATCH=100
    
  4. Get location Mọi việc gần như xong rồi. giờ thì chúng ta sẽ dựa vào kinh độ và vĩ độ để tạo map trên project của chúng ta. Đầu tiên là trong controller chúng ta sẽ trả về json để dựa vào đó chúng ta vẽ bản đồ tương ứng cho từng địa điểm. Cụ thể ở bài viết này mình sẽ vẽ địa điểm của 1 công ty nào đó, vì vậy trong action showCompaniesController mình trả về như sau:
    def show
      if request.xhr?
        render json: {
          addresses: @company.addresses
        }
      end
    end
    
    Vậy là xong việc việc trả về dữ liệu. chúng ta chuyển qua view. Đơn giản chỉ tạo 1 div chứa map và style cho nó:
    <div id="map" class="map"></div>
    
    Hoàn tất công việc bằng cách viết Javascript để xử lý dữ liệu trả về và tạo bản đồ tương ứng:
     $(function() {
       getLocation.initialize();
     });
    
     var getLocation = {
       initialize: function() {
         getLocation.fetch_data();
       },
    
       fetch_data: function() {
         var url_path = window.location.pathname;
         $.get(url_path, function(data) {
           var addresses = data['addresses'];
           const latitude = addresses[0].latitude;
           const longitude = addresses[0].longitude;
           getLocation.draw_map(latitude, longitude);
         }, 'json');
       },
    
       draw_map: function(lat, lng) {
         var companyLatlng = new google.maps.LatLng(lat, lng);
         var mapOptions = {
           zoom: 15,
           center: companyLatlng,
           mapTypeId: google.maps.MapTypeId.ROADMAP
         }
         var map = new google.maps.Map(document.getElementById('map'), mapOptions);
         var marker = new google.maps.Marker({
           position: companyLatlng,
           map: map
         });
       }
    }
    
    Ở file javascript trên mình chia thành 2 function là fetch_data để lấy dữ liệu trả về và draw_map để tạo bản đồ. Về phần draw_map thì mình chỉ custom thêm cái marker thôi. Cũng không có gì là khó hiểu nhỉ.

Conclusion

Mình đã nói qua về các tính cơ bản của Geocoder và nó còn khá nhiều tính năng thú vị nữa nên mọi người có thể tìm hiểu thêm qua Geocoder. Happy coding !