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
|
# Forge chain scopes
|
||||||
scope :in_forge_chain, ->(chain_id) { where(forge_chain_id: chain_id).order(:forge_order) }
|
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
|
# Forge chain methods
|
||||||
def forged_from_weapon
|
def forged_from_weapon
|
||||||
return nil unless forged_from.present?
|
return nil unless forged_from.present?
|
||||||
|
|
@ -188,4 +191,48 @@ class Weapon < ApplicationRecord
|
||||||
found = WeaponSeries.find_by(id: value) || WeaponSeries.find_by(slug: value)
|
found = WeaponSeries.find_by(id: value) || WeaponSeries.find_by(slug: value)
|
||||||
self.weapon_series = found
|
self.weapon_series = found
|
||||||
end
|
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
|
end
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# 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
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "btree_gin"
|
enable_extension "btree_gin"
|
||||||
enable_extension "pg_catalog.plpgsql"
|
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.integer "promotions", default: [], null: false, array: true
|
||||||
t.uuid "weapon_series_id"
|
t.uuid "weapon_series_id"
|
||||||
t.boolean "gacha", default: false, null: false
|
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 ["gacha"], name: "index_weapons_on_gacha"
|
||||||
t.index ["granblue_id"], name: "index_weapons_on_granblue_id"
|
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
|
t.index ["name_en"], name: "index_weapons_on_name_en", opclass: :gin_trgm_ops, using: :gin
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue