From fb36ac319a59c46bcbd5622d7a9b5c293e62af48 Mon Sep 17 00:00:00 2001 From: Guillem Arias Date: Mon, 18 May 2026 20:57:22 +0200 Subject: [PATCH] fix(goals): validate color format + restore cascade on drop migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add hex-format validation on Goal#color so submissions can't smuggle arbitrary CSS into the style attribute on the avatar / picker preview. The picker accepts custom hexes, so format validation (not inclusion) is the right shape — anything not matching #RRGGBB is rejected at the model boundary. - Fix the on_delete in the down block of drop_goal_contributions to match the original cascade. Restoring with restrict was a schema drift that would have shifted referential behavior after a rollback. --- app/models/goal.rb | 1 + db/migrate/20260514120001_drop_goal_contributions.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/goal.rb b/app/models/goal.rb index dbc96e4df..c020e9982 100644 --- a/app/models/goal.rb +++ b/app/models/goal.rb @@ -5,6 +5,7 @@ class Goal < ApplicationRecord ICONS = Category.icon_codes validates :icon, inclusion: { in: ICONS, allow_nil: true } + validates :color, format: { with: /\A#[0-9A-Fa-f]{6}\z/ }, allow_nil: true belongs_to :family has_many :goal_accounts, dependent: :destroy diff --git a/db/migrate/20260514120001_drop_goal_contributions.rb b/db/migrate/20260514120001_drop_goal_contributions.rb index 7feff22be..ead75eb87 100644 --- a/db/migrate/20260514120001_drop_goal_contributions.rb +++ b/db/migrate/20260514120001_drop_goal_contributions.rb @@ -6,7 +6,7 @@ class DropGoalContributions < ActiveRecord::Migration[7.2] def down create_table :goal_contributions, id: :uuid do |t| t.references :goal, null: false, foreign_key: { on_delete: :cascade }, type: :uuid - t.references :account, null: false, foreign_key: { on_delete: :restrict }, type: :uuid + t.references :account, null: false, foreign_key: { on_delete: :cascade }, type: :uuid t.decimal :amount, precision: 19, scale: 4, null: false t.string :currency, null: false t.string :source, default: "manual", null: false