mirror of
https://github.com/we-promise/sure.git
synced 2026-05-30 07:49:01 +00:00
fix(retirement): isolate retirement goals from savings goal routes
Addresses Codex P2 on #2044. A Goal::Retirement row lives in Current.family.goals, so the shared GoalsController and GoalPledgesController loaded it through `family.goals.find(...)` — never calling Goal::Retirement#editable_by?. Any preview-enabled family member could therefore open /goals/:id and edit/archive/delete another member's owner-scoped retirement plan, hit its pledge routes, and see it listed in the savings Goals grid. Adds `Goal.savings` (base type only) and scopes both savings controllers to it, so retirement goals are unreachable through the shared routes (RecordNotFound -> goals_path redirect) and absent from the savings index. Owner-only retirement access stays in RetirementController; editable_by? is retained for it. Tests: savings scope excludes retirement; retirement goal absent from goals index; show + pledge routes redirect not-found for retirement. (The Codex schema.rb null:false finding is a false positive — this branch's schema.rb retains null:false on all IBKR payload columns and the diff vs the base branch touches no IBKR lines; Codex compared against main rather than the PR base.)
This commit is contained in:
@@ -91,4 +91,15 @@ class GoalPledgesControllerTest < ActionDispatch::IntegrationTest
|
||||
get new_goal_pledge_url(other_goal)
|
||||
assert_redirected_to goals_path
|
||||
end
|
||||
|
||||
test "pledge routes are not reachable for retirement goals" do
|
||||
retirement = Goal::Retirement.create!(
|
||||
family: @user.family, owner: @user,
|
||||
name: "Retire", target_amount: 1_000_000, currency: "USD"
|
||||
)
|
||||
|
||||
get new_goal_pledge_url(retirement), headers: { "Turbo-Frame" => "modal" }
|
||||
|
||||
assert_redirected_to goals_path
|
||||
end
|
||||
end
|
||||
|
||||
@@ -239,4 +239,28 @@ class GoalsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_redirected_to goals_path
|
||||
assert_equal I18n.t("goals.errors.not_found"), flash[:alert]
|
||||
end
|
||||
|
||||
test "retirement goals are excluded from the savings index" do
|
||||
Goal::Retirement.create!(
|
||||
family: @user.family, owner: @user,
|
||||
name: "My Retirement Plan", target_amount: 1_000_000, currency: "USD"
|
||||
)
|
||||
|
||||
get goals_url
|
||||
|
||||
assert_response :success
|
||||
assert_no_match(/My Retirement Plan/, response.body)
|
||||
end
|
||||
|
||||
test "retirement goal is not reachable via the savings show route" do
|
||||
retirement = Goal::Retirement.create!(
|
||||
family: @user.family, owner: @user,
|
||||
name: "Retire", target_amount: 1_000_000, currency: "USD"
|
||||
)
|
||||
|
||||
get goal_url(retirement)
|
||||
|
||||
assert_redirected_to goals_path
|
||||
assert_equal I18n.t("goals.errors.not_found"), flash[:alert]
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user