A platform is named once: WarpEngine::Platform
The list of platforms lived on `PlatformLink::SUPPORTED_PLATFORMS` — a model
about links to a platform's website — and was copied around it four times in
the admin (`%w[tic80 ebitengine love c64 godot bevy phaser]`), spelled out in
three apipie descriptions, and turned into a class name by string
interpolation in three services:
"WarpEngine::Platforms::#{platform.camelize}::Service".constantize
Seven places that had to agree, and nothing that made them.
`WarpEngine::Platform` is now that one place. `Platform.names` is the list,
`Platform.find!("godot")` answers with a value object that knows its `label`,
its `expected_kinds` and its updater `service`, and the constantize is gone —
the registry holds the reference. `PublishService` and `BuildsService` ask it,
the admin selects read `Platform.names`, and
`PlatformLink::SUPPORTED_PLATFORMS` stays as an alias of `Platform::NAMES` so
a host pinned to 0.7 keeps working.
`Software` also defends its own value sets now. It validated neither `status`
nor `platform`, so a mistyped platform only surfaced later, at publish time,
as "Unsupported platform" — after the row existed. And `status` had three
different answers depending on where you looked: the admin offered
development/demo/released/archived, the API documentation claimed
"active, inactive", and the database holds the first four. `Software::STATUSES`
is the list, the inclusion validations enforce both, and the documentation
names the values the database actually has.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,13 +2,14 @@ module WarpEngine
|
||||
class PlatformLink < ApplicationRecord
|
||||
self.table_name = "platform_links"
|
||||
|
||||
SUPPORTED_PLATFORMS = %w[tic80 ebitengine love c64 godot bevy phaser].freeze
|
||||
SUPPORTED_PLATFORMS = WarpEngine::Platform::NAMES
|
||||
|
||||
validates :name, presence: true
|
||||
validates :url, presence: true
|
||||
validates :platform, presence: true, inclusion: { in: SUPPORTED_PLATFORMS }
|
||||
|
||||
default_scope { where(deleted_at: nil).order(:position) }
|
||||
default_scope { where(deleted_at: nil) }
|
||||
scope :ordered, -> { order(:position) }
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
%w[created_at deleted_at id name platform position updated_at url]
|
||||
@@ -19,7 +20,7 @@ module WarpEngine
|
||||
end
|
||||
|
||||
def self.for_platform(platform)
|
||||
where(platform: platform).to_a
|
||||
ordered.where(platform: platform).to_a
|
||||
end
|
||||
|
||||
ActiveSupport.run_load_hooks(:warp_engine_platform_link, self)
|
||||
|
||||
@@ -2,9 +2,11 @@ module WarpEngine
|
||||
class Software < ApplicationRecord
|
||||
self.table_name = "softwares"
|
||||
|
||||
STATUSES = %w[development demo released archived].freeze
|
||||
|
||||
belongs_to :owner, polymorphic: true, optional: true
|
||||
|
||||
has_many :software_images, foreign_key: :software_id, dependent: :destroy
|
||||
has_many :software_images, -> { ordered }, foreign_key: :software_id, dependent: :destroy
|
||||
has_many :images, through: :software_images
|
||||
has_many :releases, foreign_key: :software_id
|
||||
has_many :downloads, through: :releases
|
||||
@@ -17,7 +19,8 @@ module WarpEngine
|
||||
|
||||
validates :name, presence: true, uniqueness: true
|
||||
validates :title, presence: true
|
||||
validates :platform, presence: true
|
||||
validates :platform, presence: true, inclusion: { in: WarpEngine::Platform::NAMES }
|
||||
validates :status, inclusion: { in: STATUSES }, allow_blank: true
|
||||
|
||||
default_scope { where(deleted_at: nil) }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user