feat: add batch weather art generation jobs
- Created BatchGenerateWeatherArtsJob to process eligible cities and generate weather art. - Introduced GenerateWeatherArtJob for generating weather art and image attachment. - Added AiService for obtaining prompts and generating images with OpenAI API. - Implemented WeatherService to fetch current weather data from the QWeather API. - Updated Gemfile with necessary gems (whenever, ruby-openai, httparty, down, aws-sdk-s3). This commit introduces a system to create and store weather art images for various cities based on current weather conditions, leveraging external APIs for data and image generation.
This commit is contained in:
parent
6e387d1a8c
commit
d728d7f50e
6
Gemfile
6
Gemfile
@ -45,6 +45,12 @@ gem "devise", "~> 4.9"
|
||||
gem "activeadmin", "~> 3.2"
|
||||
gem "friendly_id", "~> 5.5"
|
||||
|
||||
gem "whenever", "~> 1.0"
|
||||
gem "ruby-openai", "~> 7.3"
|
||||
gem "httparty", "~> 0.22.0"
|
||||
gem "down", "~> 5.4"
|
||||
gem "aws-sdk-s3", "~> 1.177"
|
||||
|
||||
group :development, :test do
|
||||
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
|
||||
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"
|
||||
|
49
Gemfile.lock
49
Gemfile.lock
@ -88,6 +88,22 @@ GEM
|
||||
activesupport (>= 3.0.0)
|
||||
ruby2_keywords (>= 0.0.2)
|
||||
ast (2.4.2)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.1035.0)
|
||||
aws-sdk-core (3.215.0)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.992.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.96.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.177.0)
|
||||
aws-sdk-core (~> 3, >= 3.210.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sigv4 (1.11.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
base64 (0.2.0)
|
||||
bcrypt (3.1.20)
|
||||
bcrypt_pbkdf (1.1.1)
|
||||
@ -110,6 +126,7 @@ GEM
|
||||
rack-test (>= 0.6.3)
|
||||
regexp_parser (>= 1.5, < 3.0)
|
||||
xpath (~> 3.2)
|
||||
chronic (0.10.2)
|
||||
concurrent-ruby (1.3.5)
|
||||
connection_pool (2.5.0)
|
||||
crass (1.0.6)
|
||||
@ -127,11 +144,22 @@ GEM
|
||||
responders
|
||||
warden (~> 1.2.3)
|
||||
dotenv (3.1.7)
|
||||
down (5.4.2)
|
||||
addressable (~> 2.8)
|
||||
drb (2.2.1)
|
||||
ed25519 (1.3.0)
|
||||
erubi (1.13.1)
|
||||
et-orbi (1.2.11)
|
||||
tzinfo
|
||||
event_stream_parser (1.0.0)
|
||||
faraday (2.12.2)
|
||||
faraday-net_http (>= 2.0, < 3.5)
|
||||
json
|
||||
logger
|
||||
faraday-multipart (1.1.0)
|
||||
multipart-post (~> 2.0)
|
||||
faraday-net_http (3.4.0)
|
||||
net-http (>= 0.5.0)
|
||||
formtastic (5.0.0)
|
||||
actionpack (>= 6.0.0)
|
||||
formtastic_i18n (0.7.0)
|
||||
@ -145,6 +173,10 @@ GEM
|
||||
has_scope (0.8.2)
|
||||
actionpack (>= 5.2)
|
||||
activesupport (>= 5.2)
|
||||
httparty (0.22.0)
|
||||
csv
|
||||
mini_mime (>= 1.0.0)
|
||||
multi_xml (>= 0.5.2)
|
||||
i18n (1.14.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
inherited_resources (1.14.0)
|
||||
@ -159,6 +191,7 @@ GEM
|
||||
jbuilder (2.13.0)
|
||||
actionview (>= 5.0.0)
|
||||
activesupport (>= 5.0.0)
|
||||
jmespath (1.6.2)
|
||||
jquery-rails (4.6.0)
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
@ -204,6 +237,11 @@ GEM
|
||||
mini_mime (1.1.5)
|
||||
minitest (5.25.4)
|
||||
msgpack (1.7.5)
|
||||
multi_xml (0.7.1)
|
||||
bigdecimal (~> 3.1)
|
||||
multipart-post (2.4.1)
|
||||
net-http (0.6.0)
|
||||
uri
|
||||
net-imap (0.5.5)
|
||||
date
|
||||
net-protocol
|
||||
@ -335,6 +373,10 @@ GEM
|
||||
rubocop-minitest
|
||||
rubocop-performance
|
||||
rubocop-rails
|
||||
ruby-openai (7.3.1)
|
||||
event_stream_parser (>= 0.3.0, < 2.0.0)
|
||||
faraday (>= 1)
|
||||
faraday-multipart (>= 1)
|
||||
ruby-progressbar (1.13.0)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.4.1)
|
||||
@ -407,6 +449,8 @@ GEM
|
||||
base64
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
whenever (1.0.0)
|
||||
chronic (>= 0.6.3)
|
||||
xpath (3.2.0)
|
||||
nokogiri (~> 1.8)
|
||||
zeitwerk (2.7.1)
|
||||
@ -425,13 +469,16 @@ PLATFORMS
|
||||
|
||||
DEPENDENCIES
|
||||
activeadmin (~> 3.2)
|
||||
aws-sdk-s3 (~> 1.177)
|
||||
bootsnap
|
||||
brakeman
|
||||
capybara
|
||||
cssbundling-rails
|
||||
debug
|
||||
devise (~> 4.9)
|
||||
down (~> 5.4)
|
||||
friendly_id (~> 5.5)
|
||||
httparty (~> 0.22.0)
|
||||
jbuilder
|
||||
jsbundling-rails
|
||||
kamal
|
||||
@ -440,6 +487,7 @@ DEPENDENCIES
|
||||
puma (>= 5.0)
|
||||
rails (~> 8.0.1)
|
||||
rubocop-rails-omakase
|
||||
ruby-openai (~> 7.3)
|
||||
selenium-webdriver
|
||||
solid_cable
|
||||
solid_cache
|
||||
@ -450,6 +498,7 @@ DEPENDENCIES
|
||||
turbo-rails
|
||||
tzinfo-data
|
||||
web-console
|
||||
whenever (~> 1.0)
|
||||
|
||||
BUNDLED WITH
|
||||
2.6.2
|
||||
|
@ -21,9 +21,11 @@ ActiveAdmin.register WeatherArt do
|
||||
permit_params :city_id, :weather_date, :description, :temperature,
|
||||
:feeling_temp, :humidity, :wind_scale, :wind_speed,
|
||||
:precipitation, :pressure, :visibility, :cloud,
|
||||
:prompt, :image
|
||||
:prompt, :image, :slug
|
||||
|
||||
remove_filter :image_attachment, :image_blob
|
||||
filter :city_id
|
||||
filter :weather_data
|
||||
|
||||
index do
|
||||
selectable_column
|
||||
|
34
app/jobs/batch_generate_weather_arts_job.rb
Normal file
34
app/jobs/batch_generate_weather_arts_job.rb
Normal file
@ -0,0 +1,34 @@
|
||||
class BatchGenerateWeatherArtsJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(*args)
|
||||
start_time = Time.current
|
||||
max_duration = 50.minutes
|
||||
|
||||
cities_to_process = get_eligible_cities
|
||||
|
||||
cities_to_process.each do |city|
|
||||
break if Time.current - start_time > max_duration
|
||||
|
||||
GenerateWeatherArtJob.perform_now(city)
|
||||
sleep 1.minute # 确保不超过API限制
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_eligible_cities
|
||||
City.active
|
||||
.where(active: true)
|
||||
.where("last_weather_fetch IS NULL OR last_weather_fetch < ?", Date.today)
|
||||
# .select { |city| early_morning_in_timezone?(city.timezone) }
|
||||
end
|
||||
|
||||
# def early_morning_in_timezone?(timezone)
|
||||
# return false if timezone.blank?
|
||||
|
||||
# time = Time.current.in_time_zone(timezone)
|
||||
# time.hour == 2
|
||||
# end
|
||||
|
||||
end
|
45
app/jobs/generate_weather_art_job.rb
Normal file
45
app/jobs/generate_weather_art_job.rb
Normal file
@ -0,0 +1,45 @@
|
||||
class GenerateWeatherArtJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(*args)
|
||||
city = args[0]
|
||||
return if city.last_weather_fetch&.today?
|
||||
|
||||
weather_service = WeatherService.new
|
||||
ai_service = AiService.new
|
||||
|
||||
# 获取天气数据
|
||||
weather_data = weather_service.get_weather(city.latitude, city.longitude)
|
||||
return unless weather_data
|
||||
|
||||
# 生成提示词
|
||||
prompt = ai_service.generate_prompt(city, weather_data)
|
||||
return unless prompt
|
||||
|
||||
# 生成图像
|
||||
image_url = ai_service.generate_image(prompt)
|
||||
return unless image_url
|
||||
|
||||
# 创建天气艺术记录
|
||||
weather_art = city.weather_arts.create!(
|
||||
weather_date: Date.today,
|
||||
**weather_data,
|
||||
prompt: prompt
|
||||
)
|
||||
|
||||
# 下载并附加图像
|
||||
tempfile = Down.download(image_url)
|
||||
weather_art.image.attach(
|
||||
io: tempfile,
|
||||
filename: "#{city.country.name}-#{city.name.parameterize}-#{Time.current.strftime('%Y%m%d-%H%M%S')}.png"
|
||||
)
|
||||
|
||||
# 更新城市状态
|
||||
city.update!(
|
||||
last_weather_fetch: Time.current,
|
||||
last_image_generation: Time.current
|
||||
)
|
||||
rescue => e
|
||||
Rails.logger.error "Error generating weather art for #{city.name}: #{e.message}"
|
||||
end
|
||||
end
|
64
app/services/ai_service.rb
Normal file
64
app/services/ai_service.rb
Normal file
@ -0,0 +1,64 @@
|
||||
class AiService
|
||||
def initialize
|
||||
@client = OpenAI::Client.new(
|
||||
access_token: Rails.application.credentials.openai.token,
|
||||
uri_base: Rails.application.credentials.openai.uri,
|
||||
request_timeout: 240
|
||||
)
|
||||
end
|
||||
|
||||
def generate_prompt(city, weather_data)
|
||||
response = @client.chat(
|
||||
parameters: {
|
||||
model: "gpt-4",
|
||||
messages: [{
|
||||
role: "system",
|
||||
content: "You are a professional artist creating prompts for DALL-E 3. Create realistic, artistic weather scenes featuring iconic landmarks."
|
||||
}, {
|
||||
role: "user",
|
||||
content: generate_prompt_request(city, weather_data)
|
||||
}],
|
||||
temperature: 0.7,
|
||||
max_tokens: 300
|
||||
}
|
||||
)
|
||||
|
||||
response.dig("choices", 0, "message", "content")
|
||||
end
|
||||
|
||||
def generate_image(prompt)
|
||||
response = @client.images.generate(
|
||||
parameters: {
|
||||
model: "dall-e-3",
|
||||
prompt: prompt,
|
||||
size: "1792x1024",
|
||||
quality: "standard",
|
||||
n: 1
|
||||
}
|
||||
)
|
||||
|
||||
response.dig("data", 0, "url")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_prompt_request(city, weather_data)
|
||||
<<~PROMPT
|
||||
Create a DALL-E 3 prompt for a weather scene in #{city.name}, #{city.country.name}.
|
||||
|
||||
Weather conditions:
|
||||
- Temperature: #{weather_data[:temperature]}°C
|
||||
- Weather: #{weather_data[:description]}
|
||||
- Cloud cover: #{weather_data[:cloud]}%
|
||||
- Time: Early morning
|
||||
|
||||
Requirements:
|
||||
- Feature iconic landmarks or architecture from #{city.name}
|
||||
- Realistic style
|
||||
- Weather conditions should be clearly visible
|
||||
- Atmospheric and artistic composition
|
||||
|
||||
Generate a detailed, creative prompt that will produce a beautiful and realistic image.
|
||||
PROMPT
|
||||
end
|
||||
end
|
37
app/services/weather_service.rb
Normal file
37
app/services/weather_service.rb
Normal file
@ -0,0 +1,37 @@
|
||||
# app/services/weather_service.rb
|
||||
class WeatherService
|
||||
include HTTParty
|
||||
base_uri Rails.application.credentials.qweather.uri
|
||||
|
||||
def initialize
|
||||
@api_key = Rails.application.credentials.qweather.token
|
||||
end
|
||||
|
||||
def get_weather(latitude, longitude)
|
||||
Rails.logger.debug "Get Weather for #{latitude},#{longitude}"
|
||||
response = self.class.get(
|
||||
"/weather/now",
|
||||
headers: {
|
||||
"X-QW-Api-Key" => "#{@api_key}"
|
||||
},
|
||||
query: {
|
||||
location: "#{longitude},#{latitude}"
|
||||
})
|
||||
|
||||
return nil unless response.success?
|
||||
|
||||
data = response["now"]
|
||||
{
|
||||
temperature: data["temp"].to_f,
|
||||
feeling_temp: data["feelsLike"].to_f,
|
||||
humidity: data["humidity"].to_f,
|
||||
wind_scale: "#{data['windScale']}级",
|
||||
wind_speed: data["windSpeed"].to_f,
|
||||
precipitation: data["precip"].to_f,
|
||||
pressure: data["pressure"].to_f,
|
||||
visibility: data["vis"].to_f,
|
||||
cloud: data["cloud"].to_f,
|
||||
description: data["text"]
|
||||
}
|
||||
end
|
||||
end
|
@ -1 +1 @@
|
||||
GwoFK6l/nbuNuzqsSphWsWWAkF3rF3LqQJXbBlMhZqleAE/wXGYzxgansBULOsF+/0hMDNT+AMQdLKPd+J+Oo55LNVHd9Dk6iJ4wtRJm5Ya4czrPTqv4dezNwRFm6soC085fUONQ8hxShenYWSNtUD+X9HmjG3xDYOMk8XHJRdz+TzUqzk8+sTee1xFTP3ZFTF1HYHE+3csz22rA0KBekDbSL+HK/rlKvNK3UJK/LM71V1BmaPSBC50X+D7TkGZGatMRLPwM3C3m/6PPvB838zeH7fm2maPx2/Y4zPZhTarUg3/U+R0wGfGbSCdMMBy/A+04C7KxadTn4Ivk3zXI3zloEbgY+s1pq6RZNKuLfQFUDzpDtdnC7tjYRnMBo6C3c8iAgI0gnnYHY0zHPws+umUlS/kdiWBn6jvsNc6zz6bSyBY8xIuL4zm/Aa4wQJc5u1wLTQW00nXKJvYo7bvZsWhusATQlPm+VK+U0rdh6uAyaeatwc951KB3--N7qeSFBaRTq/dtNy--L8fWHRQMpTXu5+6E1HsNaQ==
|
||||
0Upt112zhMfb3aADOgxSWUCTTUNgtTrpoivR9+KJFKcazTjqRauvQ9W+uicYrjJjv497gHMFhusWZysDl1/uwHHaoHvyp7auIjRHiOR1YKfRLgbMSYMgSOKlP4HbiZ66hjhT+4T50JjmwwLcPFtgPaZG3lasTAXejc9ejiSn+OsIGvJje5MXnPREId5pvC/SNW4uCYMe6OEsfhTlsj8hES7odHJzMsGQGGuVkcg1EimogOE9oWK6FS0bj45R+7HCiIYlbcmDkRNraGDMGJI+oaxx2mi+34ENoxqfbYEv4PhsWPYcOROK8FyrpXwvRG/a1J8LFxTLkVloKsBIInLojvd9u8zwpcTOtsaHOxsQV7gLzUt2GbUiT4EZUdzHpIDRboJEuVxm6ioBctcJ744xnkn5rxOoJH+JWRhxf+CVLYojcYMdkcyGEOHv0nXtpWtu/xsJT3fTqJBLuyGWNQUfTDsw3qQDUOrsgSNvXvhEu1iWptoByp4d0adaCDS0+TVt+BFg2xPzSnIU3IAXgSnhyLTVd87jxBMHtcngIj4HAj+nDIs65KT4dk4Y+ns3eWE345Z0CzUz1J6M8ikva0cQiBB6wxMl1yghysCcSfKX4z/KbuJv6StQJIqw4HkDZ9youXEbnmiXTxuEaC0Yg3SE0dFf5k9Rj5govLMdCf1Msj04RQHt0b08s3UdTgegriru+j7dC6yTaDbHkrNorREME3SENzdksI1D5k08D4Z+TYpO/+yyZE5qKELEse9TgJiFZ6g1H2sFs9zCxBDif67ovFSqrRaNgP7qBY8uEfFNVP6Y6eSnfccJlFBGlwflhwwA1osit+5rKlvhqQs37qsmFZRuj9BdrAJbdr/0ogEbLyeTEw3Zq+0m0/Vf4j5ueCv2eDpk/gSQdl869v+5anLTqMUWM4KV1wS1OrPkMC5XkZHLUo1/1+Dl6FKfZhWydRso1R9WL5B0Jk7UEWMPX0qoxxuixR1jwWzYmlehq0iNw7hQPdgwCbDtRxEMPr8MkUnG5Fd0YZUfnhHJ+EWVCZHKhUJclRSB9LnDKVPJr/oFuOHLmJg6Vll4WHCnIK9nCHdr7ed6O89vA5Z8DRlE/6yAXFlPKrCldWYbrL3BAgzQK8MxD5fzgzRkGiwVEtQwhbtbdDHUJ9rdAEmLJZj1UJXLIhX9jFspB9stHqyRxrcef/Y+h9dBvuFdvSIFEXA0TWHintx9YDgsJb591d6rjJn+JYEmZs9UONEEuiijPf9waqTb0oIrUQwnlUOX69bBipiU5ZQ2yQvepuRY3ooK3IGHvngxZPT0F8Mfh5Zcx9GGJd17LZb9DJOs7uOlrpXydToq/3Qm1q6TmgjbFYpC6iyrhDyE5XLL/XwVavh7m2QYqVbUXk2tGk2C0UR6CTE6tsV1+kDs1nylIEgAA5Nr43HQtRAXPmo0k8Txy5wMMIbLE1keqjl7XdGPnLsX9CJi6ue6KZxhigwcdakvW6Y=--H101ebDKrzdM39ll--a5R5klrhU6QgghGPjjWfAQ==
|
@ -29,7 +29,8 @@ Rails.application.configure do
|
||||
config.cache_store = :memory_store
|
||||
|
||||
# Store uploaded files on the local file system (see config/storage.yml for options).
|
||||
config.active_storage.service = :local
|
||||
# config.active_storage.service = :local
|
||||
config.active_storage.service = :amazon_dev
|
||||
|
||||
# Don't care if the mailer can't send.
|
||||
config.action_mailer.raise_delivery_errors = false
|
||||
|
@ -22,7 +22,7 @@ Rails.application.configure do
|
||||
# config.asset_host = "http://assets.example.com"
|
||||
|
||||
# Store uploaded files on the local file system (see config/storage.yml for options).
|
||||
config.active_storage.service = :local
|
||||
config.active_storage.service = :amazon
|
||||
|
||||
# Assume all access to the app is happening through a SSL-terminating reverse proxy.
|
||||
config.assume_ssl = true
|
||||
|
23
config/schedule.rb
Normal file
23
config/schedule.rb
Normal file
@ -0,0 +1,23 @@
|
||||
# Use this file to easily define all of your cron jobs.
|
||||
#
|
||||
# It's helpful, but not entirely necessary to understand cron before proceeding.
|
||||
# http://en.wikipedia.org/wiki/Cron
|
||||
|
||||
# Example:
|
||||
#
|
||||
# set :output, "/path/to/my/cron_log.log"
|
||||
#
|
||||
# every 2.hours do
|
||||
# command "/usr/bin/some_great_command"
|
||||
# runner "MyModel.some_method"
|
||||
# rake "some:great:rake:task"
|
||||
# end
|
||||
#
|
||||
# every 4.days do
|
||||
# runner "AnotherModel.prune_old_records"
|
||||
# end
|
||||
every 1.hour do
|
||||
# runner "BatchGenerateWeatherArtsJob.perform_later"
|
||||
end
|
||||
|
||||
# Learn more: http://github.com/javan/whenever
|
@ -13,6 +13,21 @@ local:
|
||||
# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
|
||||
# region: us-east-1
|
||||
# bucket: your_own_bucket-<%= Rails.env %>
|
||||
amazon_dev:
|
||||
service: S3
|
||||
access_key_id: <%= ENV.fetch("AWS_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws_dev, :access_key_id)) %>
|
||||
secret_access_key: <%= ENV.fetch("AWS_SECRET_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws_dev, :secret_access_key)) %>
|
||||
region: <%= ENV.fetch("AWS_REGION", Rails.application.credentials.dig(:aws_dev, :region)) %>
|
||||
bucket: <%= ENV.fetch("AWS_BUCKET", Rails.application.credentials.dig(:aws_dev, :bucket)) %>
|
||||
endpoint: <%= ENV.fetch("AWS_ENDPOINT", Rails.application.credentials.dig(:aws_dev, :endpoint)) %>
|
||||
|
||||
amazon:
|
||||
service: S3
|
||||
access_key_id: <%= ENV.fetch("AWS_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws, :access_key_id)) %>
|
||||
secret_access_key: <%= ENV.fetch("AWS_SECRET_ACCESS_KEY_ID", Rails.application.credentials.dig(:aws, :secret_access_key)) %>
|
||||
region: <%= ENV.fetch("AWS_REGION", Rails.application.credentials.dig(:aws, :region)) %>
|
||||
bucket: <%= ENV.fetch("AWS_BUCKET", Rails.application.credentials.dig(:aws, :bucket)) %>
|
||||
endpoint: <%= ENV.fetch("AWS_ENDPOINT", Rails.application.credentials.dig(:aws, :endpoint)) %>
|
||||
|
||||
# Remember not to checkin your GCS keyfile to a repository
|
||||
# google:
|
||||
|
14
db/seeds.rb
14
db/seeds.rb
@ -139,19 +139,7 @@ Country.create!([
|
||||
Dir[Rails.root.join('db/seeds/cities/*.rb')].sort.each do |file|
|
||||
require file
|
||||
end
|
||||
|
||||
china = Country.find_by(code: 'CN')
|
||||
guangzhou = City.create!(
|
||||
name: 'Guangzhou',
|
||||
latitude: 23.1291,
|
||||
longitude: 113.2644,
|
||||
priority: 50,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
)
|
||||
guangzhou = City.find_by name: 'Guangzhou'
|
||||
|
||||
guangzhou_weather_art = WeatherArt.create!(
|
||||
city: guangzhou,
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 151.2093,
|
||||
country: australia,
|
||||
timezone: 'Australia/Sydney',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 80,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -18,7 +18,7 @@ City.create!([
|
||||
longitude: 144.9631,
|
||||
country: australia,
|
||||
timezone: 'Australia/Melbourne',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 75,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 90.4125,
|
||||
country: bangladesh,
|
||||
timezone: 'Asia/Dhaka',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 85,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: -43.1729,
|
||||
country: brazil,
|
||||
timezone: 'America/Sao_Paulo',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 80,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -6,7 +6,7 @@ City.create!(
|
||||
priority: 50,
|
||||
country: canada,
|
||||
timezone: 'America/Toronto',
|
||||
active: true,
|
||||
active: false,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
)
|
||||
|
@ -29,7 +29,7 @@ City.create!([
|
||||
longitude: 114.0579,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -51,7 +51,7 @@ City.create!([
|
||||
longitude: 104.0668,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -62,7 +62,7 @@ City.create!([
|
||||
longitude: 117.3616,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -73,7 +73,7 @@ City.create!([
|
||||
longitude: 114.3055,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -84,7 +84,7 @@ City.create!([
|
||||
longitude: 113.7518,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -95,7 +95,7 @@ City.create!([
|
||||
longitude: 106.9123,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -106,7 +106,7 @@ City.create!([
|
||||
longitude: 108.9398,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -117,7 +117,7 @@ City.create!([
|
||||
longitude: 120.1551,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -128,7 +128,7 @@ City.create!([
|
||||
longitude: 113.1216,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -139,7 +139,7 @@ City.create!([
|
||||
longitude: 118.7969,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -150,7 +150,7 @@ City.create!([
|
||||
longitude: 114.1694,
|
||||
country: china,
|
||||
timezone: 'Asia/Hong_Kong',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -161,7 +161,7 @@ City.create!([
|
||||
longitude: 123.4315,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -172,7 +172,7 @@ City.create!([
|
||||
longitude: 113.6249,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -183,7 +183,7 @@ City.create!([
|
||||
longitude: 120.3826,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -194,7 +194,7 @@ City.create!([
|
||||
longitude: 120.5853,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -205,7 +205,7 @@ City.create!([
|
||||
longitude: 112.9388,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -216,7 +216,7 @@ City.create!([
|
||||
longitude: 117.1201,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -227,7 +227,7 @@ City.create!([
|
||||
longitude: 102.7183,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -238,7 +238,7 @@ City.create!([
|
||||
longitude: 126.5340,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -249,7 +249,7 @@ City.create!([
|
||||
longitude: 114.5149,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -260,7 +260,7 @@ City.create!([
|
||||
longitude: 117.2272,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -271,7 +271,7 @@ City.create!([
|
||||
longitude: 121.6147,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -282,7 +282,7 @@ City.create!([
|
||||
longitude: 118.0819,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -293,7 +293,7 @@ City.create!([
|
||||
longitude: 108.3665,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -304,7 +304,7 @@ City.create!([
|
||||
longitude: 125.3235,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -315,7 +315,7 @@ City.create!([
|
||||
longitude: 112.5489,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -326,7 +326,7 @@ City.create!([
|
||||
longitude: 121.4657,
|
||||
country: china,
|
||||
timezone: 'Asia/Taipei',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -337,7 +337,7 @@ City.create!([
|
||||
longitude: 106.6302,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -348,7 +348,7 @@ City.create!([
|
||||
longitude: 120.3119,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -359,7 +359,7 @@ City.create!([
|
||||
longitude: 116.6822,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -370,7 +370,7 @@ City.create!([
|
||||
longitude: 87.6168,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -381,7 +381,7 @@ City.create!([
|
||||
longitude: 113.3926,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -392,7 +392,7 @@ City.create!([
|
||||
longitude: 121.5440,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -403,7 +403,7 @@ City.create!([
|
||||
longitude: 119.2965,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -414,7 +414,7 @@ City.create!([
|
||||
longitude: 115.8579,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 29.9187,
|
||||
country: egypt,
|
||||
timezone: 'Africa/Cairo',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 2.3522,
|
||||
country: france,
|
||||
timezone: 'Europe/Paris',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 8.6821,
|
||||
country: germany,
|
||||
timezone: 'Europe/Berlin',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -18,7 +18,7 @@ City.create!([
|
||||
longitude: 13.4050,
|
||||
country: germany,
|
||||
timezone: 'Europe/Berlin',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 72.8777,
|
||||
country: india,
|
||||
timezone: 'Asia/Kolkata',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -18,7 +18,7 @@ City.create!([
|
||||
longitude: 77.5946,
|
||||
country: india,
|
||||
timezone: 'Asia/Kolkata',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 139.6503,
|
||||
country: japan,
|
||||
timezone: 'Asia/Tokyo',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -18,7 +18,7 @@ City.create!([
|
||||
longitude: 139.6380,
|
||||
country: japan,
|
||||
timezone: 'Asia/Tokyo',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: -99.1332,
|
||||
country: mexico,
|
||||
timezone: 'America/Mexico_City',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 3.3792,
|
||||
country: nigeria,
|
||||
timezone: 'Africa/Lagos',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 74.3587,
|
||||
country: pakistan,
|
||||
timezone: 'Asia/Karachi',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 37.6173,
|
||||
country: russia,
|
||||
timezone: 'Europe/Moscow',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -18,7 +18,7 @@ City.create!([
|
||||
longitude: 30.3609,
|
||||
country: russia,
|
||||
timezone: 'Europe/Moscow',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 46.6753,
|
||||
country: saudi_arabia,
|
||||
timezone: 'Asia/Riyadh',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 103.8198,
|
||||
country: singapore,
|
||||
timezone: 'Asia/Singapore',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 126.9780,
|
||||
country: south_korea,
|
||||
timezone: 'Asia/Seoul',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 100.5018,
|
||||
country: thailand,
|
||||
timezone: 'Asia/Bangkok',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 28.9784,
|
||||
country: turkey,
|
||||
timezone: 'Europe/Istanbul',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -18,7 +18,7 @@ City.create!([
|
||||
longitude: 32.8597,
|
||||
country: turkey,
|
||||
timezone: 'Europe/Istanbul',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: -0.1278,
|
||||
country: uk,
|
||||
timezone: 'Europe/London',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: -122.4194,
|
||||
country: usa,
|
||||
timezone: 'America/Los_Angeles',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -18,7 +18,7 @@ City.create!([
|
||||
longitude: -87.6298,
|
||||
country: usa,
|
||||
timezone: 'America/Chicago',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -29,7 +29,7 @@ City.create!([
|
||||
longitude: -74.0060,
|
||||
country: usa,
|
||||
timezone: 'America/New_York',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -40,7 +40,7 @@ City.create!([
|
||||
longitude: -118.2437,
|
||||
country: usa,
|
||||
timezone: 'America/Los_Angeles',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
@ -7,7 +7,7 @@ City.create!([
|
||||
longitude: 106.6297,
|
||||
country: vietnam,
|
||||
timezone: 'Asia/Ho_Chi_Minh',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
@ -18,7 +18,7 @@ City.create!([
|
||||
longitude: 105.8542,
|
||||
country: vietnam,
|
||||
timezone: 'Asia/Ho_Chi_Minh',
|
||||
active: true,
|
||||
active: false,
|
||||
priority: 100,
|
||||
last_weather_fetch: 10.hours.ago,
|
||||
last_image_generation: 10.hours.ago
|
||||
|
7
test/jobs/batch_generate_weather_arts_job_test.rb
Normal file
7
test/jobs/batch_generate_weather_arts_job_test.rb
Normal file
@ -0,0 +1,7 @@
|
||||
require "test_helper"
|
||||
|
||||
class BatchGenerateWeatherArtsJobTest < ActiveJob::TestCase
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
end
|
7
test/jobs/generate_weather_art_job_test.rb
Normal file
7
test/jobs/generate_weather_art_job_test.rb
Normal file
@ -0,0 +1,7 @@
|
||||
require "test_helper"
|
||||
|
||||
class GenerateWeatherArtJobTest < ActiveJob::TestCase
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
end
|
Loading…
Reference in New Issue
Block a user