Sypex Geo на Ruby on Rails - IT-C@FE
×
Masterpro Nivo Slider (06 фев 2023)

Это форк Vinaora Nivo Slider, пришлось переименовать, в силу требования JED. Даже старую версию качать можно было только с варезных сайтов, нашпигованную троянами. Зачем оно такое, согласитесь.

Важно Sypex Geo на Ruby on Rails

Подробнее
6 года 4 мес. назад - 6 года 4 мес. назад #1 от Aleksej
Aleksej создал тему: Sypex Geo на Ruby on Rails
К материалу блога Sypex Geo на Ruby on Rails .

Отметил ряд несоответствий при использовании одной и той же базы Sypex Geo через различные адаптеры - PHP и Rails, посредством которых на одинаковый запрос БД возвращает различные значения. Списался с разработчиком гема, информация следующая: при портировании алгоритма с PHP был "зацеплен" баг с бинарным поиском, в дальнейшем баг был пофиксен одним из пользователей GitHub. На rubygems этого фикса нет, поэтому устанавливать гем оптимально именно с github (редактируем Gemfile):

gem 'sypex_geo', :git => 'git://github.com/kolesnikovde/sypex_geo.git'

Если в мастере ситуация повторится - нужно будет дебажить поиск по индексу (github.com/kolesnikovde/sypex_geo/blob/m...geo/database.rb#L105), сверяясь с PHP библиотекой.

Да, ещё один момент - код ruby библиотеки соответствует SypexGeo 2.2.3 (единственная публичная, которую можно найти на сайте), и я не уверен, что она актуальна.


К сожалению, по моим наблюдениям, кардинальных улучшений это не дает. Например, старый gem определяет координаты proxy следующим образом:

176.9.161.91
[1.63333, 111.83333]
Sarawak
Malaysia
MY

ревизия с гитхаба позволяет чуть приблизиться к реальному геотаргетингу:

176.9.161.91
[59.91273, 10.74609]
Oslo County
Norway
NO

, и только php API дает правильный результат, причем во всех трех случаях использовалась одна и та же база данных Sypex Geo:

176.9.161.91
Координаты Lat 50.48 and Lon 12.37
Falkenstein
DE

Использовать, таким образом, gem 'sypex_geo' на продакшне не представляется возможным, просьба отнестись к представленному в блоге материалу сугубо как к учебному пособию, и не более. Впрочем, есть вариант юзать на rails при определении геотаргетинга REST API Sypex Geo.

For example, убираем из Gemfile - gem 'sypex_geo' - и делаем контроллер похожим на следующие строчки кода:

class WeatherController < ApplicationController
  def index
      
      ip = request.remote_ip
      response = HTTParty.get('http://api.sypexgeo.net/json/' + ip)
      r = response.parsed_response.with_indifferent_access
      
      # @lat = r[:city][:lat]
      # @lon = r[:city][:lon]
      
      @location = r[:city][:lat],r[:city][:lon]
      @region = r[:city][:name_en]
      @country_code = r[:country][:iso]
      @timezone = r[:country][:timezone]


     @cities = "lat=#{r[:city][:lat]}&lon=#{r[:city][:lon]}"
     @lookup = Weather.call(@cities)
     @temp = Weather.max_value(Weather.make_hash(@lookup, "temp"))
     @pressure = Weather.max_value(Weather.make_hash(@lookup, "pressure"))
     @humidity = Weather.min_value(Weather.make_hash(@lookup, "humidity"))
     @clouds = Weather.min_value(Weather.cloud_hash(@lookup))
    
  end
end
Последнее редактирование: 6 года 4 мес. назад пользователем p.rishard. Причина: Добавлен рабочий пример использования REST API Sypex Geo

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Подробнее
6 года 4 мес. назад - 6 года 4 мес. назад #2 от Aleksej
Aleksej ответил в теме Sypex Geo на Ruby on Rails
Таким образом, фрагмент модели способен выглядеть теперь следующим образом (рекомендации kvokka приведены в форме комментариев):

class WeatherSxgeo < ApplicationRecord

  include HTTParty
  base_uri "http://api.openweathermap.org/data/2.5/find?&appid=*********&units=metric&cnt=10&"
  format :json
  
  def self.call list_ids
    response = HTTParty.get(base_uri + list_ids)
    body = JSON.parse(response.body)
    # Rails.logger.debug response.body
    
    # list = body["list"]
    
    # body&.fetch('list'){[]} || [] для руби 2.3+
    # ну или body.try(:fetch, 'list', []) || [] 
    # можно body.to_h.fetch 'list', []
    # можно через rescue работать (но это тупо медленнее)
    
    body.fetch('list'){[]}.compact
  end

  #create a hash to store city : temp values 
  def self.make_hash list, value
    hash = Hash.new
      list.each do |l|
        temp = l["main"][value]
        city = l["name"]
        hash[city] = temp
      end
    # return hash
  end

  #create hash with city: cloud cover
  def self.cloud_hash list
    hash = Hash.new
      list.each do |l|
        cloud = l["clouds"]["all"]
        city = l["name"]
        hash[city] = cloud
      end
    # return hash
  end

  #returns the highest value from a hash
  def self.max_value hash
    hash.max_by{|k,v| v}
  end  

  #returns the lowest value from a hash
  def self.min_value hash
    hash.min_by{ |k,v| v}
  end    

end



JSON.parse("null") # nil , а обязана выдавать всегда Hash, соответственно, можно попробовать что-то вроде:

def response_body reload: false, reraise: false
    return @_response_body if !reload && @_response_body
    @_response_body = JSON.parse(response.body) || {}
  rescue => e
    reraise ? raise(e) : {}
  end

Последнее редактирование: 6 года 4 мес. назад пользователем p.rishard.

Пожалуйста Войти или Регистрация, чтобы присоединиться к беседе.

Работает на Kunena форум