How can I store and process the geolocation (long and lat) of a website user in Rails 3, so that it checks to see if we're already holding those details in a session for that user on every page request (if we're not holding the details, then we should request the user's location from the browser and then store those details in the session)?
2 Answers
Based on your requirements I'd say that you don't actually need ajax, since most of the processing will be done using JS (to ask the user for access to their location, parse the response etc), I'd use JS to set a cookie, which Rails will then see).
In your controller
def action
@lat_lng = cookies[:lat_lng].split("|")
end
In your view
<%- unless @lat_lng %>
<script>
getGeoLocation();
</script>
<%- end %>
In one of your javascript files
function getGeoLocation() {
navigator.geolocation.getCurrentPosition(setGeoCookie);
}
function setGeoCookie(position) {
var cookie_val = position.coords.latitude + "|" + position.coords.longitude;
document.cookie = "lat_lng=" + escape(cookie_val);
}
Note that none of the above tests to see if the user has a browser that supports geolocation, or if the user has granted (or denied) permission to use their location, and that the cookie will be a session cookie, and that the JS doesn't test to see if the cookie is already set. To set more complicated information on the cookie take a look at http://www.quirksmode.org/js/cookies.html For more information on GeoLocation using javascript see http://diveintohtml5.info/geolocation.html

- 4,126
- 24
- 28
-
The downside of this solution is that some browsers (firefox, safari) will ask the user for this on every page load until they press "always share" or until the have enough and press "never allow". Any thoughts on how to get around this? – Skurpi Oct 12 '12 at 12:49
This is a very common pattern in Rails. In application_controller.rb
or application_helper.rb
(if you want it accessible from multiple controllers) define a method like
def lat_lng
@lat_lng ||= session[:lat_lng] ||= get_geolocation_data_the_hard_way
end
The ||=
bit reads "if the part on the left is nil, check the part on the right, and then assign the value to the part on the left for next time".
The @lat_lng
here is an instance variable ... probably overkill for this case since I doubt getting the session data is any actual work, but since the browser will ask for permission, you really only want to do that once. And maybe the browser doesn't have a location-aware browser, so you'll need to fall back on something else, hence the call the method get_geolocation_data_the_hard_way
which you'll have to write.

- 13,533
- 3
- 49
- 77
-
Any pointers for how to submit the ajax request, and ensure it only happens when needed? – Elliot Mar 21 '12 at 02:49
-
The `get_geolocation_data_the_hard_way` method (you can call it what you like :-) is where the request happens, e.g. to Google Maps API, which has a well documented JavaScript interface and provides all sorts of nifty geo-location, proximity-finding, and other groovy methods. If you really want to cut down on calls to the API, the method could also do something like decide what lat-lng pair was close enough for your application (e.g., if 1/2 mile is close enough) and cache or persist the results you care about for that location. But the pattern above will ensure only one call per session. – Tom Harrison Mar 21 '12 at 12:35
-
-
Well, that's an _entirely_ different question :-). You don't make the (JS) call in the controller; instead set variables needed there, then in the view add a ` – Tom Harrison Mar 21 '12 at 13:13
-
I'm actually looking to use geolocation in HTML5, so it would have to be an ajax request :) Any further suggestions? – Elliot Mar 23 '12 at 17:39
-
Hmm, two things. First, an AJAX request is (typically) made through JavaScript ... AJAX stands for Asynchronous JavaScript and XML (although the XML has been supplanted with JSON, no one has changed the name to AJAJ :-). AJAX is an HTTP request made by your browser to your server. So, the second thing is, you don't need an AJAX request to get at geolocation data from HTML5, you need to as the browser using the `navigation.geolocation` property, from JavaScript. Otherwise, everything is as I described before. – Tom Harrison Mar 23 '12 at 19:07
-
But once the navigation.geolocation method has fired, you'd need to submit an ajax request so that rails can actually make us of the data? – Elliot Mar 24 '12 at 12:34
-
Obviously I am confused about what you're asking. Sorry about that. Here's a pretty good example of how to do the AJAX request: http://notes.rehali.com/?p=97 which most of what I think you need. It sounds like you're unclear on how Rails and JS can work together and pass data in both directions. Study the example, because I think it's what you need. – Tom Harrison Mar 24 '12 at 20:35