使用Sinatra和DatamApper的地理编码器



我正在尝试在Sinatra应用程序中使用DatamApper模型使用地理编码器GEM。

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
...

我不了解什么?

首先,根据这个问题,地理位置GEM似乎不会直接支持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

以获取类级包含的顺序,还有另一种方法(这是GeoCoder Gem用于支持模型的方法:

# 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特定模块,因此您会看到该错误。

最新更新