将Geocoder与Sinatra和DataMapper一起使用

时间:2016-06-21 20:57:53

标签: ruby sinatra ruby-datamapper

我正在尝试在Sinatra应用程序中使用Geocoder gem和DataMapper模型。

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 个答案:

答案 0 :(得分:0)

首先,看起来Geocode gem不会直接支持Datamapper,as per this issue

其次,当您在类中包含模块时,这些方法可用于类的实例,而不是类级别。例如:

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 uses for supported models

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