Используйте геокодер с Sinatra и DataMapper

Я пытаюсь использовать гем Geocoder с моделью DataMapper в приложении Sinatra.

environment.rb:

require 'rubygems'
require 'bundler/setup'
require 'dm-core'
require 'dm-timestamps'
require 'dm-validations'
require 'dm-aggregates'
require 'dm-migrations'
require 'dm-types'
require 'geocoder'

require 'sinatra' unless defined?(Sinatra)

# load models
$LOAD_PATH.unshift("#{File.dirname(__FILE__)}/lib")
Dir.glob("#{File.dirname(__FILE__)}/lib/*.rb") { |lib| require File.basename(lib, '.*') }

DataMapper.setup(:default, (ENV["DATABASE_URL"] || "sqlite3:///#{File.expand_path(File.dirname(__FILE__))}/#{Sinatra::Base.environment}.db"))
DataMapper.finalize
DataMapper.auto_upgrade!

lib/location.rb:

  class Location
    include DataMapper::Resource
    include Geocoder::Model::Base

    property :id, Serial
    property :address, String, :required => true

    # geocoder gem
    geocoded_by :address, :latitude  => :lat, :longitude => :lng

    # geocoder
    after_validation :geocode, :if => :address_changed?

  end

Когда я пытаюсь начать сеанс IRB, генерируется исключение:

irb> require './environment'
NameError: uninitialized constant Geocoder::Model
...

Что я не понимаю?

1 ответ

Во-первых, похоже, что гем Geocode не будет иметь прямой поддержки Datamapper, согласно этой проблеме.

Во-вторых, когда вы включаете модуль в класс, методы доступны для экземпляра класса, а не на уровне класса. Например:

module Name
  def name
    puts "Module"
  end
end

class SomeClass
  include Name
end

SomeClass.new.name # => "Module"

Это работает, потому что, когда вы include модуль, этот модуль добавляется в цепочку предков этого класса. Любые методы, отправляемые экземпляру, которые недоступны в экземпляре, пересылаются предкам. Однако есть еще один метод extend который добавляет методы на уровне класса, а не на уровне экземпляра:

# module definition same as before

class SomeClass
  extend Name

  name # works!
end

Для того, чтобы получить включение на уровне класса, есть другой способ (который Gem GeoCoder использует для поддерживаемых моделей:

# module code same as before

module Name
  def name
    puts "Module"
  end

  def self.included(klass)
    klass.extend(self)
  end
end

included Хук предоставляется для моделей, которые могут быть переопределены, чтобы сделать что-то, когда include Name шаг выполняется. Поскольку нет специального модуля Datamapper, который не выполняет этот шаг, вы видите эту ошибку.

Другие вопросы по тегам