auto-compute forge chain fields from forged_from
- add before_save callback to calculate forge_order and forge_chain_id - add validation to prevent circular forge chains
This commit is contained in:
parent
3abc10a5e2
commit
5c578ee527
2 changed files with 54 additions and 1 deletions
|
|
@ -139,6 +139,9 @@ class Weapon < ApplicationRecord
|
|||
# Forge chain scopes
|
||||
scope :in_forge_chain, ->(chain_id) { where(forge_chain_id: chain_id).order(:forge_order) }
|
||||
|
||||
# Forge chain callbacks
|
||||
before_save :compute_forge_chain_fields, if: :forged_from_changed?
|
||||
|
||||
# Forge chain methods
|
||||
def forged_from_weapon
|
||||
return nil unless forged_from.present?
|
||||
|
|
@ -188,4 +191,48 @@ class Weapon < ApplicationRecord
|
|||
found = WeaponSeries.find_by(id: value) || WeaponSeries.find_by(slug: value)
|
||||
self.weapon_series = found
|
||||
end
|
||||
|
||||
# Validation to prevent circular forge chains
|
||||
validate :no_circular_forge_chain
|
||||
|
||||
def no_circular_forge_chain
|
||||
return unless forged_from.present?
|
||||
|
||||
visited = Set.new([granblue_id])
|
||||
current = forged_from
|
||||
|
||||
while current.present?
|
||||
if visited.include?(current)
|
||||
errors.add(:forged_from, 'creates a circular forge chain')
|
||||
return
|
||||
end
|
||||
visited << current
|
||||
current = Weapon.find_by(granblue_id: current)&.forged_from
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Auto-compute forge_order and forge_chain_id based on forged_from
|
||||
def compute_forge_chain_fields
|
||||
if forged_from.present?
|
||||
base_weapon = Weapon.find_by(granblue_id: forged_from)
|
||||
if base_weapon
|
||||
# Inherit or create forge_chain_id from base weapon
|
||||
self.forge_chain_id = base_weapon.forge_chain_id || base_weapon.id
|
||||
|
||||
# Compute forge_order as base weapon's order + 1
|
||||
self.forge_order = base_weapon.forge_order.to_i + 1
|
||||
|
||||
# Ensure base weapon has forge_chain_id if it didn't
|
||||
if base_weapon.forge_chain_id.nil?
|
||||
base_weapon.update_column(:forge_chain_id, base_weapon.id)
|
||||
base_weapon.update_column(:forge_order, 0) if base_weapon.forge_order.nil?
|
||||
end
|
||||
end
|
||||
else
|
||||
# Clearing forged_from - reset forge_order if part of a chain
|
||||
self.forge_order = 0 if forge_chain_id.present?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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_12_20_100000) do
|
||||
ActiveRecord::Schema[8.0].define(version: 2025_12_21_210000) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "btree_gin"
|
||||
enable_extension "pg_catalog.plpgsql"
|
||||
|
|
@ -989,6 +989,12 @@ ActiveRecord::Schema[8.0].define(version: 2025_12_20_100000) do
|
|||
t.integer "promotions", default: [], null: false, array: true
|
||||
t.uuid "weapon_series_id"
|
||||
t.boolean "gacha", default: false, null: false
|
||||
t.integer "extra_prerequisite"
|
||||
t.string "forged_from"
|
||||
t.uuid "forge_chain_id"
|
||||
t.integer "forge_order"
|
||||
t.index ["forge_chain_id"], name: "index_weapons_on_forge_chain_id"
|
||||
t.index ["forged_from"], name: "index_weapons_on_forged_from"
|
||||
t.index ["gacha"], name: "index_weapons_on_gacha"
|
||||
t.index ["granblue_id"], name: "index_weapons_on_granblue_id"
|
||||
t.index ["name_en"], name: "index_weapons_on_name_en", opclass: :gin_trgm_ops, using: :gin
|
||||
|
|
|
|||
Loading…
Reference in a new issue