feat(goals): gate Goals v2 behind beta features toggle

Add require_beta_features! to GoalsController and GoalPledgesController,
hide the Goals nav item for non-beta users, and tag index/show headers
with the Beta pill marker. Update controller tests to enable the
preference in setup and assert the redirect for users without access.
This commit is contained in:
Guillem Arias
2026-05-18 20:13:44 +02:00
parent ac23521c0a
commit 5c7babc44e
7 changed files with 36 additions and 6 deletions

View File

@@ -1,4 +1,5 @@
class GoalPledgesController < ApplicationController
before_action :require_beta_features!
before_action :set_goal
before_action :set_pledge, only: %i[renew destroy]
rescue_from ActiveRecord::RecordNotFound, with: :record_not_found

View File

@@ -1,4 +1,5 @@
class GoalsController < ApplicationController
before_action :require_beta_features!
before_action :set_goal, only: %i[show edit update destroy pause resume complete archive unarchive]
rescue_from ActiveRecord::RecordNotFound, with: :goal_not_found

View File

@@ -1,6 +1,9 @@
<div class="space-y-8 pb-6 lg:pb-12">
<header>
<h1 class="text-2xl font-semibold text-primary"><%= t(".title") %></h1>
<div class="flex items-center gap-2">
<h1 class="text-2xl font-semibold text-primary"><%= t(".title") %></h1>
<%= render DS::Pill.new(label: "Beta", size: :md) %>
</div>
<p class="text-sm text-secondary mt-1"><%= t(".subtitle") %></p>
</header>

View File

@@ -4,7 +4,10 @@
<%= render Goals::AvatarComponent.new(goal: @goal, size: "xl") %>
</div>
<div class="min-w-0 flex-1">
<h1 class="text-2xl font-semibold text-primary break-words"><%= @goal.name %></h1>
<div class="flex items-center gap-2 flex-wrap">
<h1 class="text-2xl font-semibold text-primary break-words"><%= @goal.name %></h1>
<%= render DS::Pill.new(label: "Beta", size: :md) %>
</div>
<p class="text-sm text-secondary mt-1"><%= @goal.header_summary %></p>
<% last_days = @goal.last_matched_pledge_days_ago %>
<% unless last_days.nil? %>

View File

@@ -11,9 +11,9 @@ else
{ name: t(".nav.transactions"), path: transactions_path, icon: "credit-card", icon_custom: false, active: page_active?(transactions_path) },
{ name: t(".nav.reports"), path: reports_path, icon: "chart-bar", icon_custom: false, active: page_active?(reports_path) },
{ name: t(".nav.budgets"), path: budgets_path, icon: "map", icon_custom: false, active: page_active?(budgets_path) },
{ name: t(".nav.goals"), path: goals_path, icon: "piggy-bank", icon_custom: false, active: page_active?(goals_path) },
(beta_features_enabled? ? { name: t(".nav.goals"), path: goals_path, icon: "piggy-bank", icon_custom: false, active: page_active?(goals_path) } : nil),
{ name: t(".nav.assistant"), path: chats_path, icon: "icon-assistant", icon_custom: true, active: page_active?(chats_path), mobile_only: true }
]
].compact
end %>
<% desktop_nav_items = mobile_nav_items.reject { |item| item[:mobile_only] } %>

View File

@@ -2,13 +2,24 @@ require "test_helper"
class GoalPledgesControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in users(:family_admin)
@user = users(:family_admin)
@user.update!(preferences: (@user.preferences || {}).merge("beta_features_enabled" => true))
sign_in @user
@goal = goals(:vacation_italy)
@account = accounts(:depository)
@pledge = goal_pledges(:open_transfer)
ensure_tailwind_build
end
test "redirects users without beta access" do
@user.update!(preferences: (@user.preferences || {}).merge("beta_features_enabled" => false))
get new_goal_pledge_url(@goal), headers: { "Turbo-Frame" => "modal" }
assert_redirected_to root_path
assert_match(/beta/i, flash[:alert])
end
test "new renders the pledge form inside a turbo frame" do
get new_goal_pledge_url(@goal), headers: { "Turbo-Frame" => "modal" }
assert_response :success

View File

@@ -2,13 +2,24 @@ require "test_helper"
class GoalsControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in users(:family_admin)
@user = users(:family_admin)
@user.update!(preferences: (@user.preferences || {}).merge("beta_features_enabled" => true))
sign_in @user
@goal = goals(:vacation_italy)
@depository = accounts(:depository)
@connected = accounts(:connected)
ensure_tailwind_build
end
test "redirects users without beta access" do
@user.update!(preferences: (@user.preferences || {}).merge("beta_features_enabled" => false))
get goals_url
assert_redirected_to root_path
assert_match(/beta/i, flash[:alert])
end
test "index renders with active filter by default" do
get goals_url
assert_response :success