2016-06-21 3 views
0

Я пытаюсь использовать драгоценный камень Geocoder с моделью DataMapper в приложении Sinatra.Использование Geocoder с Sinatra и 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 
... 

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

ответ

0

Прежде всего, похоже, что драгоценный камень Geocode не будет иметь прямой поддержки 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, который не выполняет этот шаг, вы видите эту ошибку.

+0

@craig Спасибо за редактирование! – Kashyap