Geolocalização no Rails

Natan Guedes
Jaguaribe Tech

--

É muito comum nos dias de hoje as pessoas utilizarem algum serviço de integração na Web com consulta de dados relacionados a geolocalização para se obter a latitude e a longitude de um determinado lugar, tal como encontrar onde tem um shopping ou verificar quais os lugares que você visitou recentemente.
Existe várias formas de se desenvolver aplicações de geolocalização no Rails, dentre elas, o GeoCoder. Neste artigo vamos mostrar sua configuração, como fazer a integração com Rails, e de que forma podemos localizar endereços de ruas utilizando a API GeoCode, bem como descrever os aspectos positivos e negativos de sua utilização.

Usando a API GeoCoder com Rails

À princípio, vamos preparar a aplicação Ruby on Rails para demonstrar a utilização do GeoCoder, basta abrir o prompt de comandos e seguir os passos a seguir:GeoCoder, basta abrir o prompt de comandos e seguir os passos a seguir:

$ rails new visitedPleace

Criado o projeto, vamos levar em consideração que os usuários compartilham os lugares que visitaram. Para isso, vamos criar o model Places com os seguintes campos title, visited_by, address, latitude e longitude.

Agora, vamos de fato criar o model, para isso, devemos executar o seguinte comando:

$ rails g model Places title visited_by address latitude:integer longitude:integer 

E em seguida, executamos a migração com o seguinte comando:

$ rails rake db:migrate

Para estilizar nossa aplicação, vamos adicionar o bootstrap na gemfile, adicionando da seguinte forma:

def index 
if params(:search).present?
@locations = Locations.near(params[:search],50, :order =>distance
else
@locations = location.all
end
end .

Agora, vamos de fato criar o model, para isso, devemos executar o seguinte comando:

$ rails g model Places title visited_by address latitude:integer longitude:integer

E em seguida, executamos a migração com o seguinte comando:

$ rails rake db:migrate

Para estilizar nossa aplicação, vamos adicionar o bootstrap na gemfile, adicionando da seguinte forma:

def index 
if params(:search).present?
@locations = Locations.near(params[:search],50, :order =>distance
else
@locations = location.all
end
end

Agora, iremos configurar a rota da seguinte maneira:

Rails.application.routes.draw do
resources :places do
collection do
put :get_locations
end
end
root 'places#index'
end

Por último, pode-se criar o formulário para inserir e salvar o endereço visitado:

<ul>
<% for location in @location.nearbys(10) %>
<li><%= link_to location.address, location %> (<%= location.distance.round(2) %> miles)</li>
<% end %>
</ul<% title "Location" %>
<p>
<strong>Address:</strong>
<%= @location.address %>
</p>
<p>
<strong>Latitude:</strong>
<%= @location.latitude %>
</p>
<p>
<strong>Longitude:</strong>
<%= @location.longitude %>
</p>
<h3>Nearby Locations</h3>
<ul>
<% for location in @location.nearbys(10) %>
<li><%= link_to location.address, location %> (<%= location.distance.round(2) %> miles)</li>
<% end %>
</ul>
<p>
<%= link_to "Edit", edit_location_path(@location) %> |
<%= link_to "Destroy", @location, :confirm => 'Are you sure?', :method => :delete %> |
<%= link_to "View All", locations_path %>

Integração com GeoCoder

Agora iremos falar um pouco de como fazer a integração do GeoCoder com o Rails. Para isso, vamos fazer a configuração do GeoCoder. Primeiramente, temos que instalar a gem. Existem duas formas de instalar o GeoCoder, que será explicado a seguir.
Se você estiver utilizando o Ruby, será dessa forma:

gem install geocoder

No caso do Rails, é só adicionar a gem do GeoCoder ao seu Gemfile, conforme a baixo:

gem ‘geocoder’

Configurando o GeoCoder

No GeoCoder, você pode realizar diversas configurações, como limite de tempo de pesquisa por endereço, bem como a utilização do Google Places Search API, um serviço de geocodificação. Para fazer isto, deve-se gerar um arquivo de configuração, executando o seguinte comando:

$rails generate geocoder:config

Desenvolvendo sua aplicação

Um dos maiores problemas de se trabalhar com o GeoCoder, é que você precisa ter obrigatoriamente uma chave da API para acompanhar o desenvolvimento de sua aplicação. Para fazer isso, é necessário acessar o site de desenvolvedores do Google, em seguida criar um novo projeto, mas, observando se a API de geocodificação do Google Maps está ativada. Agora é só colocar a chave da API no arquivo de inicialização.
Todo conteúdo de configuração do GeoCoder pode ser configurado em geocoder.rb localizado em config/initializers/geocoderConfig.rb. Observe como ficaria:

$rails Geocoder.configure(ip_lookup: :ipdata_co,# to use an API key:
api_key: "test",
) Geocoder.configure(

Geocodificando endereço pelo ip

Após isso, você consegue obter a localização de um determinado lugar de acordo com o endereço no qual deseja localizar.
Também se pode solicitar a GeoCodificação por endereço IP. Basta adicionar os métodos location e safe_location ao objeto Rack::Request. Feito isso, é só procurar a localização HTTP por qualquer endereço IP que você desejar. Por exemplo, em um aplicativo Sinatra ou Rails, a solicitação seria da seguinte forma :

resultados = Geocodificador.search("172.56.21.89") 
resultados . primeiro . coordenadas
# => [30.267153, -97.7430608]
resultados . primeiro . país
# => "Estados Unidos"

Uma das desvantagens do método location é vulnerabilidade à falsificação de endereço IP, o que é um problema para sua aplicação, pois ao utilizar safe_location não irá buscar pelo IP de Origem através do cabeçalho do proxy, mas você conseguirá ver a localização do último proxy. Veja que, a maioria desses métodos retornarão “nil” em seus testes, pois como a maioria dos testes são feitos localmente, ao utilizar localhost não irá funcionar, porque o mesmo não é o endereço IP da Internet.

results = Geocoder.search("172.56.21.89")
results.first.coordinates
# => [30.267153, -97.7430608]
results.first.country
# => "United States"

Próximo passo, criar um metódo chamado full_address passando o endereço completo, que ficaria da seguinte forma:

def full_address
[country, city, street].compact.join (',')
fim

Em seguida, atribuimos ao endereço completo utilizando o método geocoded_by

geocoded_by :full_address

E se o usuário estiver procurando por um endereço que não existe ou que foi alterado recentemente? Para isto, usaremos o método after_validation, onde ele irá verificar se o endereço existe ou não, da seguinte maneira:

after_validation :geocode, if: ->(obj) obj.address.present? and obj.address_changed?

Verificando se um endereço existe ou foi alterado
Agora, criamos no nosso controller.rb, o método show que irá procurar o lugar pelo respectivo id, ficando da seguinte forma:

def show
@place = Place.find(params[:id])
end

Método show que irá procurar o lugar pelo id
Em seguida criaremos nossa view, para mostrar o resultado da latitude e longitude, ou seja, o lugar que estamos procurando, mostrado da seguinte forma a seguir:

@<header><h1 class="display-4"><%= @place.title %></h1></header><p>Address: <%= @place.address %></p>
<p>Coordinates: <%= @place.latitude %> <%= @place.longitude %></p> <p>Address: <%= @place.address %></p>
<p>Coordinates: <%= @place.latitude %> <%= @place.longitude %></p>
def show
@place = Place.find(params[:id])
end

Por fim, a view exibirá os lugares com seus respectivos nomes, endereços, latitude e longitude, conforme a figura a seguir:

@<results = Geocoder.search(“Paris”)
results.first.coordinates><h1 results = Geocoder.search("Paris")
results.first.coordinates="display-4"><%= @place.title %></h1></header>

Endereços de lugares localizados pelo GeoCoder

Um ponto positivo no GeoCoder é que você pode encontrar as coordenadas de um lugar por meio de um determinado IP. Vamos exemplificar:


results = Geocoder.search("172.56.21.89")
results.first.coordinates
# => [30.267153, -97.7430608]
results.first.country
# => "United States"

Obtendo a coordenadas de um lugar a partir de um endereço IP

# encontrar o centro geográfico (também conhecido como centro de gravidade) de objetos ou pontos 
Geocoder :: Calculations . centro_geográfico ( [ cidade1 , cidade2 , [ 40,22 , — 73,99 ] , cidade4 ] )
=> [ 35,14968 , — 90,048929 ]

Outro recurso bem interessante é o fato de que você pode medir a distância dos lugares que você visitou anteriormente, para isto vamos criar um novo controlador.
Medindo distância entre os lugares que foram visitados pelo usuário
Ao criarmos nosso Distancia_controller, vamos adicionar uma nova rota para o controlador :
Adicionando rota ao Distancia_controller

def index
@current_lat = params[:lat]
@current_lon = params[:lon]
if (@current_lat.nil? || @current_lon.nil?)
@place = place.all
render json: @place
else
@place= place.near([@current_lat, @current_lon], 10, :units => :km)
end

Por último, criaremos uma nova view chamada new.html.erb que irá mostrar os lugares através do método options_from_collection_for_select, que utilizamos para gerar as tags option.

Exibição do lugares utilizando o método options_from_collection_for_select

Uma das vantagens de usar essa abordagem, é que você pode medir a distância de qualquer ponto, basta fornecer as coordenadas, como mostra o trecho de código abaixo:

obj.to_coordinates  # => [37.7941013, -122.3951096] # [lat, lon]

Utilização do método to.to_coordinates para converter o registro em uma matriz
Observe que utilizamos o método from_distance_from que recebe como parâmetro um to.to_coordinates que converte o registro em uma matriz de coordenadas da seguinte forma: [30.1, -4.3]. O uso do to_coordinates é obrigatório, caso contrário, vai gerar um erro no cálculo.
Considerações finais
O GeoCoder, apesar da suas limitações, como o fato de que o programador deve ter um cadastro no GoogleAPIS ( console.developers.google.com) para acompanhar o desenvolvimento de suas aplicações, é um dos recursos indispensáveis no Rails, principalmente quando estamos trabalhando com Geolocalização, que por meio da API GeoCoder podemos realizar diversas tarefas interessantes que vai desde localizar endereços de uma determinada rua até o registro das coordenadas dos lugares que você visitou recentemente.
Observação:
Os exemplos de códigos utilizados neste artigo, encontra-se disponíveis nesse repositório https://github.com/natanguedes/CODERubyONRails.git no GitHub.

--

--

Natan Guedes
Jaguaribe Tech

Quality Analisty (QA) e de dados e CEO da TItechgeo É graduado em Sistemas para Internet pelo IFPB Campus João Pessoa.