Compare commits

..

No commits in common. "b9801aeb6b2d7741a3b9d1796ee46619010b0b87" and "8517905b68761b57841575feb3dfba60118dbc64" have entirely different histories.

41 changed files with 10 additions and 939 deletions

View File

@ -69,7 +69,6 @@
<orderEntry type="library" scope="PROVIDED" name="et-orbi (v1.2.11, mise: 3.3.5) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="formtastic (v5.0.0, mise: 3.3.5) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="formtastic_i18n (v0.7.0, mise: 3.3.5) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="friendly_id (v5.5.1, mise: 3.3.5) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="fugit (v1.11.1, mise: 3.3.5) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="globalid (v1.2.1, mise: 3.3.5) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="has_scope (v0.8.2, mise: 3.3.5) [gem]" level="application" />

View File

@ -43,7 +43,6 @@ gem "thruster", require: false
# gem "image_processing", "~> 1.2"
gem 'devise', '~> 4.9'
gem 'activeadmin', '~> 3.2'
gem 'friendly_id', '~> 5.5'
group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem

View File

@ -135,8 +135,6 @@ GEM
formtastic (5.0.0)
actionpack (>= 6.0.0)
formtastic_i18n (0.7.0)
friendly_id (5.5.1)
activerecord (>= 4.0.0)
fugit (1.11.1)
et-orbi (~> 1, >= 1.2.11)
raabro (~> 1.4)
@ -430,7 +428,6 @@ DEPENDENCIES
cssbundling-rails
debug
devise (~> 4.9)
friendly_id (~> 5.5)
jbuilder
jsbundling-rails
kamal

View File

@ -1,54 +0,0 @@
ActiveAdmin.register City do
controller do
def find_resource
scoped_collection.friendly.find(params[:id])
end
end
# See permitted parameters documentation:
# https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#setting-up-strong-parameters
#
# Uncomment all parameters which should be permitted for assignment
#
permit_params :name, :country, :latitude, :longitude, :active, :priority, :timezone, :region, :last_weather_fetch, :last_image_generation, :slug
#
# or
#
# permit_params do
# permitted = [:name, :country, :latitude, :longitude, :active, :priority, :timezone, :region, :last_weather_fetch, :last_image_generation, :slug]
# permitted << :other if params[:action] == 'create' && current_user.admin?
# permitted
# end
index do
selectable_column
id_column
column :name
column :slug
column :latitude
column :longitude
column :active
column :created_at
actions
end
filter :name
filter :active
form do |f|
f.inputs do
f.input :active
f.input :name
f.input :country, as: :String
f.input :latitude
f.input :longitude
f.input :priority
f.input :timezone
f.input :region
f.input :last_weather_fetch
f.input :last_image_generation
end
f.actions
end
end

View File

@ -1,78 +0,0 @@
ActiveAdmin.register WeatherArt do
# See permitted parameters documentation:
# https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#setting-up-strong-parameters
#
# Uncomment all parameters which should be permitted for assignment
#
# permit_params :city_id, :weather_date, :description, :temperature, :feeling_temp, :humidity, :wind_scale, :wind_speed, :precipitation, :pressure, :visibility, :cloud, :prompt
#
# or
#
# permit_params do
# permitted = [:city_id, :weather_date, :description, :temperature, :feeling_temp, :humidity, :wind_scale, :wind_speed, :precipitation, :pressure, :visibility, :cloud, :prompt]
# permitted << :other if params[:action] == 'create' && current_user.admin?
# permitted
# end
permit_params :city_id, :weather_date, :description, :temperature,
:feeling_temp, :humidity, :wind_scale, :wind_speed,
:precipitation, :pressure, :visibility, :cloud,
:prompt, :image
remove_filter :image_attachment, :image_blob
index do
selectable_column
id_column
column :city
column :weather_date
column :description
column :temperature
column :image do |weather_art|
image_tag(weather_art.image, size: '100x100') if weather_art.image.attached?
end
actions
end
show do
attributes_table do
row :city
row :weather_date
row :description
row :temperature
row :feeling_temp
row :humidity
row :wind_scale
row :wind_speed
row :precipitation
row :pressure
row :visibility
row :cloud
row :prompt
row :image do |weather_art|
image_tag(weather_art.image) if weather_art.image.attached?
end
end
end
form do |f|
f.inputs do
f.input :city
f.input :weather_date
f.input :description
f.input :temperature
f.input :feeling_temp
f.input :humidity
f.input :wind_scale
f.input :wind_speed
f.input :precipitation
f.input :pressure
f.input :visibility
f.input :cloud
f.input :prompt
f.input :image, as: :file
end
f.actions
end
end

View File

@ -1,9 +0,0 @@
class CitiesController < ApplicationController
def index
@cities = City.all.order(:name)
end
def show
@city = City.friendly.find(params[:id])
end
end

View File

@ -1,6 +0,0 @@
class HomeController < ApplicationController
def index
@latest_arts = WeatherArt.includes(:city).order(created_at: :desc).limit(6)
@featured_arts = WeatherArt.includes(:city).order(created_at: :desc).limit(5)
end
end

View File

@ -1,6 +0,0 @@
class WeatherArtsController < ApplicationController
def show
@city = City.friendly.find(params[:city_id])
@weather_art = @city.weather_arts.find(params[:id])
end
end

View File

@ -1,2 +0,0 @@
module CitiesHelper
end

View File

@ -1,2 +0,0 @@
module HomeHelper
end

View File

@ -1,2 +0,0 @@
module WeatherArtsHelper
end

View File

@ -3,9 +3,4 @@ class AdminUser < ApplicationRecord
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable,
:recoverable, :rememberable, :validatable
def self.ransackable_attributes(auth_object = nil)
# 列出你想要允许搜索的属性
%w[created_at email id updated_at]
end
end

View File

@ -1,23 +0,0 @@
class City < ApplicationRecord
extend FriendlyId
friendly_id :name, use: :slugged
has_many :weather_arts, dependent: :destroy
validates :name, presence: true
validates :latitude, presence: true
validates :longitude, presence: true
def should_generate_new_friendly_id?
name_changed? || super
end
def self.ransackable_associations(auth_object = nil)
[ "weather_arts" ]
end
def self.ransackable_attributes(auth_object = nil)
["active", "country", "created_at", "id", "id_value", "last_image_generation", "last_weather_fetch", "latitude", "longitude", "name", "priority", "region", "slug", "timezone", "updated_at"]
end
end

View File

@ -1,16 +0,0 @@
class WeatherArt < ApplicationRecord
belongs_to :city
has_one_attached :image
validates :weather_date, presence: true
validates :city_id, presence: true
def self.ransackable_associations(auth_object = nil)
["city", "image_attachment", "image_blob"]
end
def self.ransackable_attributes(auth_object = nil)
[ "city_id", "cloud", "created_at", "description", "feeling_temp", "humidity", "id", "id_value", "precipitation", "pressure", "prompt", "temperature", "updated_at", "visibility", "weather_date", "wind_scale", "wind_speed" ]
end
end

View File

@ -1,18 +0,0 @@
<div class="space-y-8">
<h1 class="text-3xl font-bold">Cities</h1>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<% @cities.each do |city| %>
<div class="card bg-base-200">
<div class="card-body">
<h2 class="card-title"><%= city.name %></h2>
<p>Latitude: <%= city.latitude %></p>
<p>Longitude: <%= city.longitude %></p>
<div class="card-actions justify-end">
<%= link_to "View Weather Art", city_path(city), class: "btn btn-primary" %>
</div>
</div>
</div>
<% end %>
</div>
</div>

View File

@ -1,49 +0,0 @@
<div class="space-y-8">
<div class="flex justify-between items-center">
<h1 class="text-3xl font-bold"><%= @city.name %></h1>
<%= link_to "Back to Cities", cities_path, class: "btn btn-ghost" %>
</div>
<div class="stats shadow">
<div class="stat">
<div class="stat-title">Latitude</div>
<div class="stat-value"><%= @city.latitude %></div>
</div>
<div class="stat">
<div class="stat-title">Longitude</div>
<div class="stat-value"><%= @city.longitude %></div>
</div>
</div>
<div class="space-y-4">
<h2 class="text-2xl font-bold">Weather Art History</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<% @city.weather_arts.order(weather_date: :desc).each do |art| %>
<div class="card bg-base-200">
<figure>
<% if art.image.attached? %>
<%= image_tag art.image, class: "w-full h-48 object-cover" %>
<% end %>
</figure>
<div class="card-body">
<h3 class="card-title"><%= art.weather_date.strftime("%Y-%m-%d") %></h3>
<p><%= art.description %></p>
<div class="stats stats-vertical shadow">
<div class="stat">
<div class="stat-title">Temperature</div>
<div class="stat-value"><%= art.temperature %>°C</div>
</div>
<div class="stat">
<div class="stat-title">Humidity</div>
<div class="stat-value"><%= art.humidity %>%</div>
</div>
</div>
<div class="card-actions justify-end">
<%= link_to "View Details", city_weather_art_path(@city, art), class: "btn btn-primary" %>
</div>
</div>
</div>
<% end %>
</div>
</div>
</div>

View File

@ -1,46 +0,0 @@
<div class="space-y-8">
<!-- 头部标题 -->
<div class="text-center space-y-4">
<h1 class="text-4xl font-bold">AI Weather Art</h1>
<p class="text-xl text-base-content/70">Discover the beauty of weather through AI-generated art</p>
</div>
<!-- 轮播图 -->
<div class="carousel w-full rounded-box">
<% WeatherArt.last(5).each_with_index do |art, index| %>
<div id="slide<%= index %>" class="carousel-item relative w-full">
<% if art.image.attached? %>
<%= image_tag art.image, class: "w-full aspect-video object-cover" %>
<% end %>
<div class="absolute flex justify-between transform -translate-y-1/2 left-5 right-5 top-1/2">
<a href="#slide<%= index == 0 ? 4 : index - 1 %>" class="btn btn-circle"></a>
<a href="#slide<%= index == 4 ? 0 : index + 1 %>" class="btn btn-circle"></a>
</div>
</div>
<% end %>
</div>
<!-- 最新天气艺术 -->
<div class="space-y-4">
<h2 class="text-2xl font-bold">Latest Weather Art</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<% WeatherArt.last(6).each do |art| %>
<div class="card bg-base-200">
<figure>
<% if art.image.attached? %>
<%= image_tag art.image, class: "w-full h-48 object-cover" %>
<% end %>
</figure>
<div class="card-body">
<h3 class="card-title"><%= art.city.name %></h3>
<p><%= art.weather_date.strftime("%Y-%m-%d") %></p>
<p><%= art.description %></p>
<div class="card-actions justify-end">
<%= link_to "View Details", city_weather_art_path(art.city, art), class: "btn btn-primary" %>
</div>
</div>
</div>
<% end %>
</div>
</div>
</div>

View File

@ -18,30 +18,12 @@
<link rel="apple-touch-icon" href="/icon.png">
<%# Includes all stylesheet files in app/assets/stylesheets %>
<%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
<%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
</head>
<body class="min-h-screen bg-base-100">
<div class="navbar bg-base-100">
<div class="container mx-auto">
<div class="flex-1">
<%= link_to "AI Weather Art", root_path, class: "btn btn-ghost normal-case text-xl" %>
</div>
<div class="flex-none">
<%= link_to "Cities", cities_path, class: "btn btn-ghost normal-case" %>
</div>
</div>
</div>
<main class="container mx-auto px-4 py-8">
<body>
<%= yield %>
</main>
<footer class="footer footer-center p-4 bg-base-200 text-base-content">
<div>
<p>Copyright © 2024 - All rights reserved by AI Weather Art</p>
</div>
</footer>
</body>
</html>

View File

@ -1,46 +0,0 @@
<div class="space-y-8">
<div class="flex justify-between items-center">
<h1 class="text-3xl font-bold"><%= @weather_art.city.name %> - <%= @weather_art.weather_date.strftime("%Y-%m-%d") %></h1>
<%= link_to "Back to City", city_path(@weather_art.city), class: "btn btn-ghost" %>
</div>
<div class="card lg:card-side bg-base-200 shadow-xl">
<figure class="lg:w-1/2">
<% if @weather_art.image.attached? %>
<%= image_tag @weather_art.image, class: "w-full h-full object-cover" %>
<% end %>
</figure>
<div class="card-body lg:w-1/2">
<h2 class="card-title"><%= @weather_art.description %></h2>
<div class="stats stats-vertical shadow">
<div class="stat">
<div class="stat-title">Temperature</div>
<div class="stat-value"><%= @weather_art.temperature %>°C</div>
<div class="stat-desc">Feels like <%= @weather_art.feeling_temp %>°C</div>
</div>
<div class="stat">
<div class="stat-title">Wind</div>
<div class="stat-value"><%= @weather_art.wind_scale %></div>
<div class="stat-desc"><%= @weather_art.wind_speed %> km/h</div>
</div>
<div class="stat">
<div class="stat-title">Humidity</div>
<div class="stat-value"><%= @weather_art.humidity %>%</div>
</div>
<div class="stat">
<div class="stat-title">Visibility</div>
<div class="stat-value"><%= @weather_art.visibility %> km</div>
</div>
</div>
<div class="mt-4">
<h3 class="font-bold">AI Prompt:</h3>
<p class="text-sm"><%= @weather_art.prompt %></p>
</div>
</div>
</div>
</div>

View File

@ -4,12 +4,12 @@ ActiveAdmin.setup do |config|
# Set the title that is displayed on the main layout
# for each of the active admin pages.
#
config.site_title = "Today Ai Weather Admin"
config.site_title = "Today Ai Weather"
# Set the link url for the title. For example, to take
# users to your main site. Defaults to no link.
#
config.site_title_link = "/"
# config.site_title_link = "/"
# Set an optional image to be displayed for the header
# instead of a string (overrides :site_title)

View File

@ -1,107 +0,0 @@
# FriendlyId Global Configuration
#
# Use this to set up shared configuration options for your entire application.
# Any of the configuration options shown here can also be applied to single
# models by passing arguments to the `friendly_id` class method or defining
# methods in your model.
#
# To learn more, check out the guide:
#
# http://norman.github.io/friendly_id/file.Guide.html
FriendlyId.defaults do |config|
# ## Reserved Words
#
# Some words could conflict with Rails's routes when used as slugs, or are
# undesirable to allow as slugs. Edit this list as needed for your app.
config.use :reserved
config.reserved_words = %w[new edit index session login logout users admin
stylesheets assets javascripts images]
# This adds an option to treat reserved words as conflicts rather than exceptions.
# When there is no good candidate, a UUID will be appended, matching the existing
# conflict behavior.
# config.treat_reserved_as_conflict = true
# ## Friendly Finders
#
# Uncomment this to use friendly finders in all models. By default, if
# you wish to find a record by its friendly id, you must do:
#
# MyModel.friendly.find('foo')
#
# If you uncomment this, you can do:
#
# MyModel.find('foo')
#
# This is significantly more convenient but may not be appropriate for
# all applications, so you must explicitly opt-in to this behavior. You can
# always also configure it on a per-model basis if you prefer.
#
# Something else to consider is that using the :finders addon boosts
# performance because it will avoid Rails-internal code that makes runtime
# calls to `Module.extend`.
#
# config.use :finders
#
# ## Slugs
#
# Most applications will use the :slugged module everywhere. If you wish
# to do so, uncomment the following line.
#
# config.use :slugged
#
# By default, FriendlyId's :slugged addon expects the slug column to be named
# 'slug', but you can change it if you wish.
#
# config.slug_column = 'slug'
#
# By default, slug has no size limit, but you can change it if you wish.
#
# config.slug_limit = 255
#
# When FriendlyId can not generate a unique ID from your base method, it appends
# a UUID, separated by a single dash. You can configure the character used as the
# separator. If you're upgrading from FriendlyId 4, you may wish to replace this
# with two dashes.
#
# config.sequence_separator = '-'
#
# Note that you must use the :slugged addon **prior** to the line which
# configures the sequence separator, or else FriendlyId will raise an undefined
# method error.
#
# ## Tips and Tricks
#
# ### Controlling when slugs are generated
#
# As of FriendlyId 5.0, new slugs are generated only when the slug field is
# nil, but if you're using a column as your base method can change this
# behavior by overriding the `should_generate_new_friendly_id?` method that
# FriendlyId adds to your model. The change below makes FriendlyId 5.0 behave
# more like 4.0.
# Note: Use(include) Slugged module in the config if using the anonymous module.
# If you have `friendly_id :name, use: slugged` in the model, Slugged module
# is included after the anonymous module defined in the initializer, so it
# overrides the `should_generate_new_friendly_id?` method from the anonymous module.
#
# config.use :slugged
# config.use Module.new {
# def should_generate_new_friendly_id?
# slug.blank? || <your_column_name_here>_changed?
# end
# }
#
# FriendlyId uses Rails's `parameterize` method to generate slugs, but for
# languages that don't use the Roman alphabet, that's not usually sufficient.
# Here we use the Babosa library to transliterate Russian Cyrillic slugs to
# ASCII. If you use this, don't forget to add "babosa" to your Gemfile.
#
# config.use Module.new {
# def normalize_friendly_id(text)
# text.to_slug.normalize! :transliterations => [:russian, :latin]
# end
# }
end

View File

@ -1,20 +1,4 @@
Rails.application.routes.draw do
root "home#index"
resources :cities, only: [ :index, :show ] do
resources :weather_arts, only: [ :show ]
end
# namespace :admin do
# resources :cities
# resources :weather_arts
# root to: "cities#index"
# end
get "weather_arts/show"
get "cities/index"
get "cities/show"
get "home/index"
devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self)
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

View File

@ -1,18 +0,0 @@
class CreateCities < ActiveRecord::Migration[8.0]
def change
create_table :cities do |t|
t.string :name
t.string :country
t.float :latitude
t.float :longitude
t.boolean :active
t.integer :priority
t.string :timezone
t.string :region
t.datetime :last_weather_fetch
t.datetime :last_image_generation
t.timestamps
end
end
end

View File

@ -1,6 +0,0 @@
class AddSlugToCities < ActiveRecord::Migration[8.0]
def change
add_column :cities, :slug, :string
add_index :cities, :slug, unique: true
end
end

View File

@ -1,21 +0,0 @@
MIGRATION_CLASS =
if ActiveRecord::VERSION::MAJOR >= 5
ActiveRecord::Migration["#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"]
else
ActiveRecord::Migration
end
class CreateFriendlyIdSlugs < MIGRATION_CLASS
def change
create_table :friendly_id_slugs do |t|
t.string :slug, null: false
t.integer :sluggable_id, null: false
t.string :sluggable_type, limit: 50
t.string :scope
t.datetime :created_at
end
add_index :friendly_id_slugs, [:sluggable_type, :sluggable_id]
add_index :friendly_id_slugs, [:slug, :sluggable_type], length: {slug: 140, sluggable_type: 50}
add_index :friendly_id_slugs, [:slug, :sluggable_type, :scope], length: {slug: 70, sluggable_type: 50, scope: 70}, unique: true
end
end

View File

@ -1,21 +0,0 @@
class CreateWeatherArts < ActiveRecord::Migration[8.0]
def change
create_table :weather_arts do |t|
t.references :city, null: false, foreign_key: true
t.date :weather_date
t.string :description
t.decimal :temperature
t.decimal :feeling_temp
t.decimal :humidity
t.string :wind_scale
t.decimal :wind_speed
t.decimal :precipitation
t.decimal :pressure
t.decimal :visibility
t.decimal :cloud
t.text :prompt
t.timestamps
end
end
end

View File

@ -1,57 +0,0 @@
# This migration comes from active_storage (originally 20170806125915)
class CreateActiveStorageTables < ActiveRecord::Migration[7.0]
def change
# Use Active Record's configured type for primary and foreign keys
primary_key_type, foreign_key_type = primary_and_foreign_key_types
create_table :active_storage_blobs, id: primary_key_type do |t|
t.string :key, null: false
t.string :filename, null: false
t.string :content_type
t.text :metadata
t.string :service_name, null: false
t.bigint :byte_size, null: false
t.string :checksum
if connection.supports_datetime_with_precision?
t.datetime :created_at, precision: 6, null: false
else
t.datetime :created_at, null: false
end
t.index [ :key ], unique: true
end
create_table :active_storage_attachments, id: primary_key_type do |t|
t.string :name, null: false
t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
t.references :blob, null: false, type: foreign_key_type
if connection.supports_datetime_with_precision?
t.datetime :created_at, precision: 6, null: false
else
t.datetime :created_at, null: false
end
t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true
t.foreign_key :active_storage_blobs, column: :blob_id
end
create_table :active_storage_variant_records, id: primary_key_type do |t|
t.belongs_to :blob, null: false, index: false, type: foreign_key_type
t.string :variation_digest, null: false
t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true
t.foreign_key :active_storage_blobs, column: :blob_id
end
end
private
def primary_and_foreign_key_types
config = Rails.configuration.generators
setting = config.options[config.orm][:primary_key_type]
primary_key_type = setting || :primary_key
foreign_key_type = setting || :bigint
[ primary_key_type, foreign_key_type ]
end
end

81
db/schema.rb generated
View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.0].define(version: 2025_01_19_032348) do
ActiveRecord::Schema[8.0].define(version: 2025_01_18_163460) do
create_table "active_admin_comments", force: :cascade do |t|
t.string "namespace"
t.text "body"
@ -25,34 +25,6 @@ ActiveRecord::Schema[8.0].define(version: 2025_01_19_032348) do
t.index ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource"
end
create_table "active_storage_attachments", force: :cascade do |t|
t.string "name", null: false
t.string "record_type", null: false
t.bigint "record_id", null: false
t.bigint "blob_id", null: false
t.datetime "created_at", null: false
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
end
create_table "active_storage_blobs", force: :cascade do |t|
t.string "key", null: false
t.string "filename", null: false
t.string "content_type"
t.text "metadata"
t.string "service_name", null: false
t.bigint "byte_size", null: false
t.string "checksum"
t.datetime "created_at", null: false
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
end
create_table "active_storage_variant_records", force: :cascade do |t|
t.bigint "blob_id", null: false
t.string "variation_digest", null: false
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
end
create_table "admin_users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
@ -64,55 +36,4 @@ ActiveRecord::Schema[8.0].define(version: 2025_01_19_032348) do
t.index ["email"], name: "index_admin_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_admin_users_on_reset_password_token", unique: true
end
create_table "cities", force: :cascade do |t|
t.string "name"
t.string "country"
t.float "latitude"
t.float "longitude"
t.boolean "active"
t.integer "priority"
t.string "timezone"
t.string "region"
t.datetime "last_weather_fetch"
t.datetime "last_image_generation"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "slug"
t.index ["slug"], name: "index_cities_on_slug", unique: true
end
create_table "friendly_id_slugs", force: :cascade do |t|
t.string "slug", null: false
t.integer "sluggable_id", null: false
t.string "sluggable_type", limit: 50
t.string "scope"
t.datetime "created_at"
t.index ["slug", "sluggable_type", "scope"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope", unique: true
t.index ["slug", "sluggable_type"], name: "index_friendly_id_slugs_on_slug_and_sluggable_type"
t.index ["sluggable_type", "sluggable_id"], name: "index_friendly_id_slugs_on_sluggable_type_and_sluggable_id"
end
create_table "weather_arts", force: :cascade do |t|
t.integer "city_id", null: false
t.date "weather_date"
t.string "description"
t.decimal "temperature"
t.decimal "feeling_temp"
t.decimal "humidity"
t.string "wind_scale"
t.decimal "wind_speed"
t.decimal "precipitation"
t.decimal "pressure"
t.decimal "visibility"
t.decimal "cloud"
t.text "prompt"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["city_id"], name: "index_weather_arts_on_city_id"
end
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "weather_arts", "cities"
end

View File

@ -7,39 +7,4 @@
# ["Action", "Comedy", "Drama", "Horror"].each do |genre_name|
# MovieGenre.find_or_create_by!(name: genre_name)
# end
AdminUser.create!(email: 'admin@example.com', password: 'password', password_confirmation: 'password') if Rails.env.development?
guangzhou = City.create!(
name: 'Guangzhou',
country: 'China',
latitude: 23.1291,
longitude: 113.2644,
active: true,
priority: 50,
timezone: 'Asia/Shanghai',
region: 'Asia',
last_weather_fetch: 10.hours.ago,
last_image_generation: 10.hours.ago
)
guangzhou_weather_art = WeatherArt.create!(
city: guangzhou,
weather_date: Date.today,
description: 'Sunny with some clouds',
temperature: 28.5,
feeling_temp: 30.2,
humidity: 65,
wind_scale: "3级",
wind_speed: 15,
precipitation: 0,
pressure: 1013,
visibility: 10,
cloud: 30,
prompt: "A sunny day in Guangzhou with modern buildings under blue sky and white clouds, digital art style"
)
guangzhou_weather_art.image.attach(
io: File.open("db/seeds/images/sample-guangzhou-weather-art.png"),
filename: "sample-guangzhou-weather-art.png",
content_type: "image/png"
)
AdminUser.create!(email: 'admin@example.com', password: 'password', password_confirmation: 'password') if Rails.env.development?

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

49
package-lock.json generated
View File

@ -15,7 +15,6 @@
"tailwindcss": "^3.4.17"
},
"devDependencies": {
"daisyui": "^4.12.23",
"esbuild": "^0.24.2"
}
},
@ -546,17 +545,6 @@
"node": ">= 8"
}
},
"node_modules/css-selector-tokenizer": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
"integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==",
"dev": true,
"license": "MIT",
"dependencies": {
"cssesc": "^3.0.0",
"fastparse": "^1.1.2"
}
},
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@ -569,36 +557,6 @@
"node": ">=4"
}
},
"node_modules/culori": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/culori/-/culori-3.3.0.tgz",
"integrity": "sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}
},
"node_modules/daisyui": {
"version": "4.12.23",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.12.23.tgz",
"integrity": "sha512-EM38duvxutJ5PD65lO/AFMpcw+9qEy6XAZrTpzp7WyaPeO/l+F/Qiq0ECHHmFNcFXh5aVoALY4MGrrxtCiaQCQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"css-selector-tokenizer": "^0.8",
"culori": "^3",
"picocolors": "^1",
"postcss-js": "^4"
},
"engines": {
"node": ">=16.9.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/daisyui"
}
},
"node_modules/detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
@ -708,13 +666,6 @@
"node": ">=8.6.0"
}
},
"node_modules/fastparse": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
"integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
"dev": true,
"license": "MIT"
},
"node_modules/fastq": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz",

View File

@ -2,7 +2,6 @@
"name": "app",
"private": true,
"devDependencies": {
"daisyui": "^4.12.23",
"esbuild": "^0.24.2"
},
"scripts": {

View File

@ -4,8 +4,5 @@ module.exports = {
'./app/helpers/**/*.rb',
'./app/assets/stylesheets/**/*.css',
'./app/javascript/**/*.js'
],
plugins: [
require('daisyui'),
],
]
}

View File

@ -1,13 +0,0 @@
require "test_helper"
class CitiesControllerTest < ActionDispatch::IntegrationTest
test "should get index" do
get cities_index_url
assert_response :success
end
test "should get show" do
get cities_show_url
assert_response :success
end
end

View File

@ -1,8 +0,0 @@
require "test_helper"
class HomeControllerTest < ActionDispatch::IntegrationTest
test "should get index" do
get home_index_url
assert_response :success
end
end

View File

@ -1,8 +0,0 @@
require "test_helper"
class WeatherArtsControllerTest < ActionDispatch::IntegrationTest
test "should get show" do
get weather_arts_show_url
assert_response :success
end
end

View File

@ -1,29 +0,0 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
#one:
# name: MyString
# country: MyString
# slug: MyString
# latitude: 1.5
# longitude: 1.5
# active: false
# priority: 1
# timezone: MyString
# population: 1
# region: MyString
# last_weather_fetch: 2025-01-19 10:28:26
# last_image_generation: 2025-01-19 10:28:26
#
#two:
# name: MyString
# country: MyString
# slug: MyString
# latitude: 1.5
# longitude: 1.5
# active: false
# priority: 1
# timezone: MyString
# population: 1
# region: MyString
# last_weather_fetch: 2025-01-19 10:28:26
# last_image_generation: 2025-01-19 10:28:26

View File

@ -1,31 +0,0 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
one:
city: one
weather_date: 2025-01-19
description: MyString
temperature: 9.99
feeling_temp: 9.99
humidity: 9.99
wind_scale: MyString
wind_speed: 9.99
precipitation: 9.99
pressure: 9.99
visibility: 9.99
cloud: 9.99
prompt: MyText
two:
city: two
weather_date: 2025-01-19
description: MyString
temperature: 9.99
feeling_temp: 9.99
humidity: 9.99
wind_scale: MyString
wind_speed: 9.99
precipitation: 9.99
pressure: 9.99
visibility: 9.99
cloud: 9.99
prompt: MyText

View File

@ -1,7 +0,0 @@
require "test_helper"
class CityTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end

View File

@ -1,7 +0,0 @@
require "test_helper"
class WeatherArtTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end

View File

@ -467,34 +467,11 @@ cross-spawn@^7.0.0:
shebang-command "^2.0.0"
which "^2.0.1"
css-selector-tokenizer@^0.8:
version "0.8.0"
resolved "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz"
integrity sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==
dependencies:
cssesc "^3.0.0"
fastparse "^1.1.2"
cssesc@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz"
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
culori@^3:
version "3.3.0"
resolved "https://registry.npmjs.org/culori/-/culori-3.3.0.tgz"
integrity sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==
daisyui@^4.12.23:
version "4.12.23"
resolved "https://registry.npmjs.org/daisyui/-/daisyui-4.12.23.tgz"
integrity sha512-EM38duvxutJ5PD65lO/AFMpcw+9qEy6XAZrTpzp7WyaPeO/l+F/Qiq0ECHHmFNcFXh5aVoALY4MGrrxtCiaQCQ==
dependencies:
css-selector-tokenizer "^0.8"
culori "^3"
picocolors "^1"
postcss-js "^4"
detect-libc@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz"
@ -577,11 +554,6 @@ fast-glob@^3.3.2:
merge2 "^1.3.0"
micromatch "^4.0.8"
fastparse@^1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz"
integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==
fastq@^1.6.0:
version "1.18.0"
resolved "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz"
@ -836,7 +808,7 @@ path-scurry@^1.11.1:
lru-cache "^10.2.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
picocolors@^1, picocolors@^1.0.1, picocolors@^1.1.1:
picocolors@^1.0.1, picocolors@^1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz"
integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
@ -865,7 +837,7 @@ postcss-import@^15.1.0:
read-cache "^1.0.0"
resolve "^1.1.7"
postcss-js@^4, postcss-js@^4.0.1:
postcss-js@^4.0.1:
version "4.0.1"
resolved "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz"
integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==
@ -956,7 +928,7 @@ run-parallel@^1.1.9:
sass@^1.83.4:
version "1.83.4"
resolved "https://registry.npmjs.org/sass/-/sass-1.83.4.tgz"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.83.4.tgz#5ccf60f43eb61eeec300b780b8dcb85f16eec6d1"
integrity sha512-B1bozCeNQiOgDcLd33e2Cs2U60wZwjUUXzh900ZyQF5qUasvMdDZYbQ566LJu7cqR+sAHlAfO6RMkaID5s6qpA==
dependencies:
chokidar "^4.0.0"