Ceci est le premier message de Qiita! Puisque je suis débutant, je pense qu'il y a de nombreux points que je ne peux pas atteindre, mais je vous serais reconnaissant de bien vouloir commenter!
ruby: 2.7.1 rails: 6.0.3.2
Accédez à la page d'accueil d'OpenWeatherMap et accédez à Connexion et créez un compte avec Créer un compte. Si vous l'activez à partir de l'e-mail envoyé, vous recevrez une clé API.
Enregistrez-le en tant que variable d'environnement ou «informations d'identification». Cette fois, nous utiliserons les «informations d'identification». En ce qui concerne les informations d'identification, l '[article] de cette personne (https://qiita.com/NaokiIshimura/items/2a179f2ab910992c4d39) est très utile.
EDITOR=vi bin/rails credentials:edit
credentials.yml.enc
open_weahter:
appid: <API_KEY>
uri: https://samples.openweathermap.org/data/2.5/forecast
De plus, puisque je vais avoir la météo toutes les 3 heures cette fois, je reçois l'URI pour envoyer la requête en me référant au document API.
Il semble qu'il existe de nombreux types de conditions météorologiques qui peuvent être obtenues même avec le niveau gratuit! Il est intéressant de rechercher divers documents API.
Téléchargez city.list.json
depuis la documentation de l'API (https://openweathermap.org/forecast5). ![Capture d'écran 2020-08-02 15.54.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684915/9535a511-db9d-f4b3-f042- 028b93b1c498.png)
À partir de ce fichier, obtenez le CITY ID de la ville que vous souhaitez obtenir. Ceci est un extrait partiel du contenu. À propos, lon signifie longitude et lat signifie latitude.
city.list.json
{
"id": 1850147,
"name": "Tokyo",
"state": "",
"country": "JP",
"coord": {
"lon": 139.691711,
"lat": 35.689499
}
},
Je pleurais pour avoir cette identité ... Veuillez noter que certaines villes du même nom ont des latitudes et des longitudes différentes!
Si vous utilisez Excel ou mac, vous devez les lister en chiffres et les convertir en CSV! Au fait, le CSV que j'ai créé ressemble à ceci. Je racle quelques colonnes.
db/csv/cities.csv
Sapporo,2128295
Aomori,2130658
Morioka,2111834
Sendai,2111149
Akita,2113126
Yamagata,2110556
Fukushima,2112923
Mito,2111901
Utsunomiya,1849053
Maebashi,1857843
Saitama,6940394
Chiba,2113015
Tokyo,1850147
Yokohama,1848354
Niigata,1855431
Toyama,1849876
Kanazawa,1860243
Fukui,1863983
Yamanashi,1848649
Nagano,1856215
Gifu,1863640
Shizuoka,1851715
Nagoya,1856057
Tsu,1849796
Otsu,1853574
Kyoto,1857910
Osaka,1853909
Kobe,1859171
Nara,1855612
Wakayama,1926004
Tottori,1849890
Matsue,1857550
Okayama,1854383
Hiroshima,1862415
Yamaguchi,1848689
Tokushima,1850158
Takamatsu,1851100
Matsuyama,1926099
Kochi,1859146
Fukuoka,1863967
Saga,1853303
Nagasaki,1856177
Kumamoto,1858421
Oita,1854487
Miyazaki,1856717
Kagoshima,1860827
Naha,1856035
Écrivez le code dans seeds.rb
ou task
et enregistrez-le dans la base de données. Cette fois, je l'ai implémenté sous lib / tasks
. CITY ID stocke le nom de la colonne en tant que location_id
.
import_csv.rake
desc 'Import cities'
task cities: [:environment] do
list = []
CSV.foreach('db/csv/cities.csv') do |row|
list << {
name: row[0],
location_id: row[1],
}
end
puts 'start creating cities'
begin
City.create!(list)
puts 'completed!'
rescue ActiveModel::UnknownAttributeError
puts 'raised error: unknown attributes'
end
end
Chargez le fichier cities.csv
créé précédemment avec la méthode CSV.foreach ligne par ligne. Vous pouvez obtenir le nom de la ville dans la première colonne avec row [0]
et le CITY ID dans la deuxième colonne avec row [1]
, alors créez un tableau de hachages et enregistrez-le dans la base de données avec City.create!
Je suis.
Avant d'implémenter la requête HTTP, analysez d'abord le fichier JSON de la réponse.
Document API a une explication détaillée de chaque élément, alors reportez-vous-y pour obtenir la clé des données que vous souhaitez. Une demande pour une ville sera renvoyée au format JSON comme indiqué ci-dessous. (Si vous utilisez la commande curl ou VScode, vous devriez l'essayer avec REST Client.)
example_resopnse.json
{
"cod": "200",
"message": 0,
"cnt": 40,
"list": [
{
"dt": 1578409200,
"main": {
"temp": 284.92,
"feels_like": 281.38,
"temp_min": 283.58,
"temp_max": 284.92,
"pressure": 1020,
"sea_level": 1020,
"grnd_level": 1016,
"humidity": 90,
"temp_kf": 1.34
},
"weather": [
{
"id": 804,
"main": "Clouds",
"description": "overcast clouds",
"icon": "04d"
}
],
"clouds": {
"all": 100
},
"wind": {
"speed": 5.19,
"deg": 211
},
"sys": {
"pod": "d"
},
"dt_txt": "2020-01-07 15:00:00"
},
Cette fois, je crée un tableau en utilisant les éléments suivants.
«Pluie» est ajouté à la liste uniquement s'il y a des précipitations.
Veuillez vous référer à ici pour l'ID météo. OpenWeatherMap classe la météo par ID. Il est également possible d'obtenir la météo à partir de «description». Cependant, comme il existe de nombreux types, dans cette implémentation, l'ID météo est stocké dans la base de données et la météo est attribuée par la méthode.
Tout d'abord, ajoutez httpclient à votre Gemfile et à bundle install
.
gem 'httpclient', '~> 2.8', '>= 2.8.3'
Créez ensuite lib / api / open_weather_map / request.rb
.
Je pensais qu'il n'était pas nécessaire de le rendre si profond, mais j'ai décidé d'organiser les fichiers comme celui-ci en tenant compte de l'implémentation d'autres classes pour cette api et de l'implémentation d'autres classes api.
Par défaut, seule la tâche est chargée sous lib, donc les paramètres suivants sont requis dans config / application.rb
. Puisqu'il s'agit de ʻeager_load_paths`, l'environnement de production est également correct.
config/application.rb
config.paths.add 'lib', eager_load: true
Je serais très heureux si vous pouviez souligner des points tels que «Hé, c'est génial». Le placement des fichiers était le plus gros problème avec cette implémentation ...
Tableau WeatherForecast pour enregistrer les demandes ↓
WeatherForecast | |
---|---|
temp_max | float |
temp_min | float |
temp_feel | float |
weather_id | int |
rainfall | float |
date | datetime |
aquired_at | datetime |
Voici la classe Request implémentée.
request.rb
module Api
module OpenWeatherMap
class Request
attr_accessor :query
def initialize(location_id)
@query = {
id: location_id,
units: 'metric',
appid: Rails.application.credentials.open_weather[:appid],
}
end
def request
client = HTTPClient.new
request = client.get(Rails.application.credentials.open_weather[:uri], query) #La valeur de retour correspond aux données pendant 5 jours toutes les 3 heures
JSON.parse(request.body)
end
def self.attributes_for(attrs)
rainfall = attrs['rain']['3h'] if attrs['rain']
date = attrs['dt_txt'].in_time_zone('UTC').in_time_zone
{
temp_max: attrs['main']['temp_max'],
temp_min: attrs['main']['temp_min'],
temp_feel: attrs['main']['feels_like'],
weather_id: attrs['weather'][0]['id'],
rainfall: rainfall,
date: date,
aquired_at: Time.current,
}
end
end
end
end
Je mets la chaîne de requête avec ʻinitialize. La chaîne de requête requise pour cette demande ajoute
location_id et API KEY pour indiquer l'ID de VILLE, et ʻunits: 'metric'
pour changer l'affichage de la température en degrés Celsius.
Afin de convertir la requête retournée en une forme qui peut être enregistrée dans la base de données, la méthode ʻattributes_for` est transformée en méthode de classe.
Ce à quoi vous devez faire attention est la quantité de précipitations et la date de prévision.
--Pour les précipitations, il n'y a pas d'élément s'il n'y a pas de précipitations. Par conséquent, il est conditionnel de ne l'obtenir que lorsque c'est le cas.
Pour la gestion des fuseaux horaires, reportez-vous à cet article.
Je veux enregistrer / mettre à jour régulièrement la base de données, donc je l'écrirai dans rake task
.
Cela dit, j'ai écrit la plupart des méthodes de la classe Request
plus tôt, donc tout ce que j'ai à faire est de les utiliser.
open_weather_api.rake
namespace :open_weather_api do
desc 'Requests and save in database'
task weather_forecasts: :environment do
City.all.each do |city|
open_weather = Api::OpenWeatherMap::Request.new(city.location_id)
#Limite de demande: 60 fois/min
response = open_weather.request
#Économisez 2 jours de données toutes les 3 heures
16.times do |i|
params = Api::OpenWeatherMap::Request.attributes_for(response['list'][i])
if weather_forecast = WeatherForecast.where(city: city, date: params[:date]).presence
weather_forecast[0].update!(params)
else
city.weather_forecasts.create!(params)
end
end
end
puts 'completed!'
end
end
Cette fois, nous avons fait une spécification pour sauvegarder et mettre à jour les données toutes les 3 heures dans la base de données pendant 2 jours. Le point est la limite de demande et s'il s'agit de création ou de mise à jour de données.
presence
est une méthode qui appelle la méthode present?
Et renvoie le récepteur lui-même si elle est vraie. Si la même prévision de temps pour la même ville existe déjà dans la base de données, ʻupdate! Est appelé, sinon
create! `Est appelé.Si vous préparez une icône météo correspondant au weather_id
sauvegardé, cela ressemblera à une prévision météo!
Je pense que c'est une bonne idée de frapper régulièrement api avec cron ou heroku schedular
pour heroku!
C'était affiché comme ça!
Merci d'avoir lu le long texte!
https://openweathermap.org/api https://qiita.com/yoshito410kam/items/26c3c6e519d4990ed739
Recommended Posts