In JavaScript, I can easily get my current Latitude and Longitude Coordinates and I'm trying to implement this in Ruby On Rails
In Javascript, I can use the following code to get my current Latitude and Longitude.
var x = document.getElementById("demo");
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
x.innerHTML = "Geolocation is not supported by this browser.";
}
}
function showPosition(position) {
x.innerHTML = "Latitude: " + position.coords.latitude +
"<br>Longitude: " + position.coords.longitude;
}
In Rails, I am able to get my current IP address using the following
Net::HTTP.get(URI.parse('http://checkip.amazonaws.com/')).squish
However, I am unable to convert this to a latitude and longitude,
The Javascript approach asks the users permission to use their current location which would be ideal for the scenario I am facing. I realise that there are gems out there that tackle this problem however I need this to work on localhost which the javascript method does.
geocoder
gem will not work with localhost. And if to use it in production it can only give approximate results.
More precise result can be received by sending ajax request from frontend to backend.
<!-- application.html.erb -->
<!DOCTYPE html>
<html>
<head>
<%= javascript_include_tag 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js' %>
<%= javascript_include_tag 'https://cdnjs.cloudflare.com/ajax/libs/noty/3.1.0/noty.js' %>
<%= stylesheet_link_tag 'https://cdnjs.cloudflare.com/ajax/libs/noty/3.1.0/noty.min.css' %>
<script>
// It's bad to write inline javascript. To be moved into separate .js file
$(function() {
Noty.overrideDefaults({ theme: 'relax', layout: 'topCenter' });
$('.getLocation').click(function(e) {
event.preventDefault();
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
$('.latInput').val(position.coords.latitude);
$('.longInput').val(position.coords.longitude);
new Noty({
text: "Got location",
type: "success"
}).show();
}, function(position) {
new Noty({
text: "Could not get location",
type: "error"
}).show();
});
} else {
new Noty({
text: "Geolocation is not supported by this browser.",
type: "error"
}).show();
}
});
$('.resetLocation').click(function(e) {
event.preventDefault();
$('.latInput').val('');
$('.longInput').val('');
});
$('.submitAjax').click(function(e) {
event.preventDefault();
var lat = $('.latInput').val();
var long = $('.longInput').val();
if (lat && long) {
$.ajax({
url: "/",
data: {
lat: lat,
long: long
}
}).done(function() {
new Noty({
text: "Data was successfully submitted to server via AJAX",
type: "success"
}).show();
}).fail(function() {
new Noty({
text: "Couldn't send data",
type: "error"
}).show();
});
} else {
new Noty({
text: "Click on 'Get Location' button first",
type: "error"
}).show();
}
});
$('.clearAndSubmit').click(function(e) {
$('.latInput').val('');
$('.longInput').val('');
});
});
</script>
</head>
<body>
<%
ip = request.remote_ip
ip = '8.8.8.8' if ip.in?(["::1", "127.0.0.1"])
%>
Geocoder.search(ip):
<br />
<textarea cols="50" rows="10"><%= Geocoder.search(ip) %></textarea>
<hr />
<% if params[:lat].present? && params[:long].present? %>
Form was submitted:
<br />
Lat: <%= params[:lat] %>
<br />
Long: <%= params[:lat] %>
<% else %>
Form was not submitted
<% end %>
<br />
<br />
<%= form_tag '/', method: :get do |f| %>
<button class="getLocation">Get Location</button>
<button class="resetLocation">Reset Location</button>
<br />
<br />
<%= label_tag :lat, 'Lat:' %>
<%= text_field_tag :lat, params[:lat], class: 'latInput' %>
<%= label_tag :long, 'Long:' %>
<%= text_field_tag :long, params[:long], class: 'longInput' %>
<br />
<br />
<button class="submitAjax">Submit location to server via ajax</button>
<br />
<br />
<%= submit_tag "Submit location to server via form submit" %>
<br />
<br />
<button class="clearAndSubmit">Clear form and submit</button>
<% end %>
</body>
</html>
# application_controller.rb
class ApplicationController < ActionController::Base
before_action do
# Implemented before_action for demonstration purposes. Should be moved into action.
if params[:lat].present? && params[:long].present?
Rails.logger.info(['Received lat&long from AJAX request', {lat: params[:lat], long: params[:long]}])
# current_user.lat = params[:lat]
# current_user.lat = params[:lng]
# current_user.save!
end
end
end
# gemfile.rb
#...
gem 'geocoder'