Search code examples
javascripthtmlruby-on-railsgeolocationgeokit

How to use AJAX request to pass user's HTML5 location in a class variable from JavaScript to Rails controller?


I'm using Ruby (2.7.2p137), Ruby on Rails (v6.0.3.4) and Geokit-rails (2.3.2).

I'm trying to pass the user's location into a method from the Geokit-rails gem. To do this, I am trying to use an AJAX request to pass user's HTML5 location from JavaScript to Rails controller.

Update: Class variables were required to do this rather than instance variables. This is explained in the answer.

Below is the error/response from the server when the show_location method is called:

Started GET "/show_location?user_location%5B%7B%3Avalue%3D%3Enil%7D%5D=" for ::1 at 2021-02-21 13:03:18 +0000
Processing by PropertiesController#show_location as HTML
  Parameters: {"user_location"=>{"{:value=>nil}"=>""}}
Completed 500 Internal Server Error in 2ms (ActiveRecord: 0.0ms | Allocations: 1235)  
  
NoMethodError (undefined method `*' for nil:NilClass):

app/controllers/properties_controller.rb:77:in `show_location'

The following response is showing on the server so the JavaScript in index.js appears to be working:

Started POST "/user_long" for ::1 at 2021-02-21 12:57:13 +0000
Started POST "/user_lat" for ::1 at 2021-02-21 12:57:13 +0000
Processing by PropertiesController#user_lat as */*
  Parameters: {"lat"=>"53.3200896"}
No template found for PropertiesController#user_lat, rendering head :no_content
Completed 204 No Content in 80ms (ActiveRecord: 0.0ms | Allocations: 2885)


Processing by PropertiesController#user_long as */*
  Parameters: {"long"=>"-6.2521344"}
No template found for PropertiesController#user_long, rendering head :no_content
Completed 204 No Content in 34ms (ActiveRecord: 0.0ms | Allocations: 2340)

Here is the HTML5 location object logged to the console in the browser:

Object
latitude: 53.3200896
longitude: -6.2521344
__proto__: Object

Below is the JavaScript from my index.js file that requests the HTML5 location:

//function that gets the location and returns it
function getLocation() {
  if(navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(showPosition);
  } else {
    console.log("Geo Location not supported by browser");
  }
}

//function that retrieves the position
function showPosition(position) {
  var location = {
    latitude: position.coords.latitude,
    longitude: position.coords.longitude
  }

  $(document).ready(function() {
    var lat = $(this).val();
    $.ajax({
        type: 'post',
        url: '/user_lat',
        data: {lat: position.coords.latitude},
    success: function(data) {
      console.log(data);
    }
    });      
  })

  $(document).ready(function() {
    var long = $(this).val();
    $.ajax({
        type: 'post',
        url: '/user_long',
        data: {long: position.coords.longitude},
    success: function(data) {
      console.log(data);
    }
    });      
  })

  console.log(location)
}

//request for location
getLocation();

This is the method within my Rails controller (properties_controller.rb) that shows a list of properties by distance based on specified coordinates:

def show_location

    @user_lat = user_lat

    @user_long = user_long

    @properties = Property.by_distance(:origin => [@user_lat, @user_long])

end

Here are the methods in my properties controller for the AJAX request:

  def user_lat
    @user_lat = params["lat"]
  end

  def user_long
    @user_long = params["long"]
  end

I know that the gem and controller is working because when I hard code the coordinates into the show_location method, it works successfully. Working method below.

  def show_location
    
    @properties = Property.by_distance(:origin => [53.3200896,-6.2521344])

  end

So I just need help to pass the user's location into this method.

With the above code, I receive the following error:

undefined method `*' for nil:NilClass

relating to the line:

@properties = Property.by_distance(:origin => [@user_lat, @user_long])

Any help appreciated.


Solution

  • I figured this out. The AJAX request was working however the methods inside the properties_controller were storing the user's latitude and longitude to instance variables rather than class variables.

    The instance variables can't be used/accessed outside the method whereas the class variables can be used/accessed in any method within the class.

    This is corrected below in the properties_controller.rb :

      def user_lat
        @@user_lat = params["lat"]
        session[:user_lat] = @@user_lat
      end
    
      def user_long
        @@user_long = params["long"]
        session[:user_long] = @@user_long
      end
    

    Then the class variables are passed into the show_location method.

    def show_location
        @properties = Property.by_distance(:origin => [@@user_lat, @@user_long])
    end