×
Покер бот на Ruby on Rails (12 сен 2018)

Третья ипостась покера на ruby. Искреннее спасибо всем, кто прислал замечания по предыдущим релизам.

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

Больше
1 год 3 мес. назад - 1 год 2 мес. назад #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
Последнее редактирование: 1 год 2 мес. назад пользователем p.rishard. Причина: Добавлен рабочий пример использования REST API Sypex Geo

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

Больше
1 год 2 мес. назад - 1 год 2 мес. назад #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

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

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