Geokit Gem 1.5 и Ruby 1.9.2 => «несовместимые кодировки символов: UTF-8 и ASCII-8BIT» - PullRequest
0 голосов
/ 16 августа 2010

В настоящее время я пишу приложение для рельсов с использованием новейших технологий. Rails3, rSpec2, Ruby 1.9.2 и Geokit 1.5.0. Когда я пытаюсь геокодировать адреса, которые имеют специальные символы, которых нет в ASCII-8Bit, я получаю эту ошибку:

несовместимые кодировки символов: UTF-8 и ASCII-8BIT

След выглядит так:

1) Spot Basic Validations should calculate lat and lng
    Failure/Error: spot = Spot.create!({
    incompatible character encodings: UTF-8 and ASCII-8BIT
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/geokit-1.5.0/lib/geokit/geocoders.rb:435:in `do_geocode'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/geokit-1.5.0/lib/geokit/geocoders.rb:126:in `geocode'
    # ./app/models/spot.rb:26:in `geocode_address'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activesupport-3.0.0.rc/lib/active_support/callbacks.rb:409:in `_run_validation_callbacks'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activemodel-3.0.0.rc/lib/active_model/validations/callbacks.rb:53:in `run_validations!'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activemodel-3.0.0.rc/lib/active_model/validations.rb:168:in `valid?'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/validations.rb:55:in `valid?'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/validations.rb:75:in `perform_validations'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/validations.rb:49:in `save!'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/attribute_methods/dirty.rb:30:in `save!'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/transactions.rb:242:in `block in save!'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/transactions.rb:289:in `block in with_transaction_returning_status'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/connection_adapters/abstract/database_statements.rb:139:in `transaction'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/transactions.rb:204:in `transaction'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/transactions.rb:287:in `with_transaction_returning_status'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/transactions.rb:242:in `save!'
    # /Users/nilsriedemann/.rvm/gems/ruby-1.9.2-rc2/gems/activerecord-3.0.0.rc/lib/active_record/validations.rb:34:in `create!'
    # ./spec/models/spot_spec.rb:13:in `block (2 levels) in <top (required)>'

Я использовал # coding: utf-8 во всех моих связанных файлах (спецификации, фабрики и модели). Тем не менее, я получаю эту ошибку, когда использую адрес типа «Elsassers Straße 27».

Есть намеки? Я думал, что Geokit уже совместим с 1.9.1 и, следовательно, со всей этой новой функцией кодирования.

Ответы [ 5 ]

3 голосов
/ 06 июля 2011

Использование CGI.escape не очень хорошая идея, так как дает неожиданные результаты. Попробуйте "Осло, Норвегия" с и без CGI.escape, вы поймете, что я имею в виду.

Лучшее решение - использовать Iconv на месте:

ic = Iconv.new('US-ASCII//IGNORE', 'UTF-8')
utf8location = ic.iconv(location)

ура!

РЕДАКТИРОВАТЬ: У меня было предложение Уэса Гэмбла для редактирования здесь, которое я считаю уместным:

Использование //IGNORE удалит все не-ASCII символы. Но во многих (большинстве) случаях вы можете захотеть транслитерировать определенные символы, такие как умлауты (например, «Цюрих» станет «Цюрих») или Carons (например, «Ниш» станет «Ниш»), чтобы успешно геокодировать их. Если вы игнорируете символы, не входящие в ASCII, то «Zürich» станет «Zrich», а «Niš» станет «Ni», ни один из которых не будет успешно геокодирован.

Для этого вы хотите использовать

ic = Iconv.new('US-ASCII//TRANSLIT', 'UTF-8')

Обратите внимание, что преобразование вызовет исключение, если транслитерация не может быть завершена, поэтому убедитесь, что вы справились с этим.

1 голос
/ 01 сентября 2011

CGI.escape представляется более точным, чем Geokit :: Inflector :: url_escape.

Вот результаты кодировки "Elsassers Straße 27"

>> CGI.escape(address)

=> "Elsassers+Stra%C3%9Fe+27"

Пока

>> Geokit::Inflector::url_escape(address)

=> "Elsassers+Stra%C3e+27"

Буква ß должна отображаться как c39F (согласно http://www.utf8 -chartable.de / unicode-utf8-table.pl )

Кроме того, оператор debug взрывался (я знал, что была причина проверить, включено ли ведение журнала отладки:)

Итак, вот мое решение для GoogleGeocoder3, я думаю, у других будет похожая проблема

module Geokit
  module Geocoders
    class GoogleGeocoder3 < Geocoder
      def self.do_geocode(address, options = {})
        bias_str = options[:bias] ? construct_bias_string_from_options(options[:bias]) : ''
        address_str = address.is_a?(GeoLoc) ? address.to_geocodeable_s : address
        #use CGI.escape instead of Geokit::Inflector::url_escape
        url ="http://maps.google.com/maps/api/geocode/json?sensor=false&address=#{CGI.escape(address_str)}#{bias_str}"
        res = self.call_geocoder_service(url)
        return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
        json = res.body
        # escape results of json
        logger.debug "Google geocoding. Address: #{address}. Result: #{CGI.escape(json)}"
        return self.json2GeoLoc(json, address)
      end
    end
  end
end
0 голосов
/ 10 февраля 2011

Я знаю, что это очень очень поздний ответ, но я написал геокодер Google для гема Geokit, который обрабатывает все эти ошибки несовместимости.Этот геокодер использует новейший V3 API службы геокодирования Google.Преимущество состоит в том, что теперь он не анализирует XML, а скорее JSON, который работает быстрее, в сочетании с требуемым гемом Yajl (супер быстрый json-анализатор для ruby) работает намного быстрее.Мои тесты показывают примерно в 1,5 раза быстрее, чем старый.

https://github.com/rubymaniac/geokit-gem

0 голосов
/ 06 июня 2011

У меня была та же проблема, и я решил ее, добавив CGI.escape () следующим образом:

geo = Geokit::Geocoders::MultiGeocoder.geocode(CGI.escape(address))
0 голосов
/ 25 сентября 2010

Вы используете Postgres и pg gem v0.8?Обновление до 0,9

...