Search code examples
ruby-on-railsrubyherokupumargeo

Undefined method on Heroku (using Puma)


We're using the Postgis adapter with Ruby on Rails, and we're trying to use Puma on Heroku for our production environment. Our test pass flawlessly on the development system. Also, the server works perfectly on every production server but Heroku, but once we run it on Heroku + Puma (or Unicron), we get an exception.

As a side note, the application works smoothly when deployed using Webrick on Heroku.

When using puma (and at a later try, unicorn) as the default web server, everything goes well but one thing:

I'm using RGeo gem to keep track of some hive locations. When switched to Puma (Unicorn), calling @hive.current_location.lon and @hive.current_location.lat in my Javascript views throws the error:

ActionView::Template::Error (undefined method 'lon' and 'lat' for #<RGeo::Cartesian::PointImpl:0x007f700846c970>)

Meanwhile, I tried to access the current_location latitude and longitude through heroku run rails console

The interesting thing is that fetching lat and long values on Heroku console returns correct values. It seems that the problem results from puma and unicorn.

Any suggestion?


Solution

  • Finally I found the solution for this. Read this post.

    Further details:

    Basically, in my hive model I use:

    set_rgeo_factory_for_column(:current_location, 
                              RGeo::Geographic.spherical_factory(:srid => 4326))
    

    And then in my location creator I have the following code:

    require_relative "./coordinate_builder"
    require 'rgeo'
    
    class LocationCreator
      DEFAULT = "default"
    
      def self.create(lat_lng)
        return nil if lat_lng == DEFAULT
    
        lng, lat = CoordinateBuilder.parse(lat_lng)
        geographic_factory = RGeo::Geographic.spherical_factory
        geographic_factory.point(lng, lat)
      end
    end
    

    Later in the views, I use the following piece of code to fetch the latitude and longitude of the points in order to create a Google Maps marker and pin it on a map:

    <% if @hive.current_location.present? %>
      var myLatlng = new google.maps.LatLng(<%= @hive.current_location.latitude %>, <%[email protected]_location.longitude %>);
      var mapOptions = {
        zoom: 16,
        center: myLatlng,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      }
    <% end  %>
    

    Problem: Apparently Rgeo::Geographic::SphericalPointImpl falls back to RGeo::Cartesian::PointImpl in my Javascript code.

    Workaround: I changed my javascript calls from @hive.current_location.lat to @hive.current_location.y. Also for latitude, I did the same: @hive.current_location.lon to @hive.current_location.x.

    This fixed the problem for me.