Problems implementing ruby geocoder using Sinatra

2019-07-22 00:34发布

问题:

According to the ruby geocoder documentation (rubygeocoder.com), it's possible to use the geocoder gem with a Sinatra app, but I'm running into issues getting it to work and haven't been able to find any working examples or related stackoverflow issues either. I think the problem is due to the fact that it's a Sinatra app and not a full rails app.

My Gemfile:

source "https://rubygems.org"
ruby '2.1.2'
gem 'dotenv', '~> 0.10.0'
gem 'pg', '~> 0.17.1'
gem 'rack-flash3'
gem "sinatra"
gem "activerecord"
gem "sinatra-activerecord"
gem "geocoder"
gem 'omniauth'
gem 'omniauth-google-oauth2'
gem "sqlite3"
gem "shotgun"

The model (which has float latitude and longitude columns) that I want to search by:

class Item < ActiveRecord::Base  
 extend Geocoder::Model::ActiveRecord

  attr_accessor :latitude, :longitude
  belongs_to :profile
  has_and_belongs_to_many :categories
  has_many :reports, dependent: :destroy
}

Here's the app.rb code with the '/' route:

class FL < Sinatra::Base
  get '/' do
    @items = Item.near('Detroit, MI, US')
    puts "ITEMS ARE:"
    pp @items
    erb :index
  end
  ...
end

Here's the relevant app.rb contents:

require 'rubygems'
require 'sinatra/base'
require 'sinatra/flash'
require 'sinatra/activerecord'
require 'geocoder'
require 'omniauth'
require 'sinatra/flash'
require 'json'
require 'pp'
require 'rack-flash'
require './models/model_init'
require './helpers/helper'
require './auth'
require './admin'
require './api'

class FL < Sinatra::Base

  set :root, File.dirname(__FILE__)

  enable :logging
  enable :sessions
  #set :logging, true

  register Sinatra::ActiveRecordExtension
  register Sinatra::Flash

  set :show_exceptions, true if ENV['RACK_ENV'] == 'development'

  use Rack::Session::Cookie, :secret => ENV['RACK_COOKIE_SECRET']

end

Finally, here is the error i receive:

NoMethodError - undefined method `near' for #<Class:0x0000010750d0b8>:
/Users/bob/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.0/lib/active_record/dynamic_matchers.rb:26:in `method_missing'
/Users/bob/rails_projects/fl2/api.rb:21:in `block in <class:FL>'
/Users/bob/.rvm/gems/ruby-2.1.2/gems/sinatra-1.4.5/lib/sinatra/base.rb:1603:in `call'
/Users/bob/.rvm/gems/ruby-2.1.2/gems/sinatra-1.4.5/lib/sinatra/base.rb:1603:in `block in compile!'
/Users/bob/.rvm/gems/ruby-2.1.2/gems/sinatra-1.4.5/lib/sinatra/base.rb:966:in `[]'
/Users/bob/.rvm/gems/ruby-2.1.2/gems/sinatra-1.4.5/lib/sinatra/base.rb:966:in `block (3 levels) in route!'

Looking at the stacktrace, it looks like its not finding the geocoder package for some reason. I'm not sure if if it's a simple configuration that I'm missing, or if what I'm attempting isn't possible without some gem customization (something beyond my understanding at this point). Any insight, suggestions to try, or examples would be much appreciated. thanks!

Adding my config.ru:

config.ru

require 'bundler/setup'
Bundler.require(:default)

use Bundler.setup(:default)  #added this by suggestion

require 'logger'
use Rack::Deflater

Dotenv.load

require "./fl_app"
run FL

回答1:

I found a solution to this issue, but can't explain why it works. I had to add the line:

  reverse_geocoded_by :latitude, :longitude

to my Item model. Once I added that line I was able to use geocoder's 'near' method.

Even though I'm not actually doing any geocoding (converting lat/long to addresses, or vice versa), it still appears to be necessary for the library to work correctly. Thanks @iain for all your helpful advice.