Extract Users::JoinsController from overloaded UsersController

Good code smell is when the before_action callbacks stack up but can't
be shared across actions
This commit is contained in:
David Heinemeier Hansson
2025-11-02 17:49:25 +01:00
parent ada599f6a2
commit 43069b1ea4
7 changed files with 71 additions and 55 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ module Authorization
if Current.membership.blank?
redirect_to session_menu_url(script_name: nil)
elsif Current.user.nil? && Current.membership.join_code.present?
redirect_to new_user_path
redirect_to new_users_join_path
elsif !Current.user&.active?
redirect_to unlink_membership_url(script_name: nil, membership_id: Current.membership.signed_id(purpose: :unlinking))
end
+32
View File
@@ -0,0 +1,32 @@
class Users::JoinsController < ApplicationController
require_access_without_a_user
before_action :set_join_code, :ensure_join_code_is_valid
def new
end
def create
@join_code.redeem do
User.create!(user_params.merge(membership: Current.membership))
end
redirect_to root_path
end
private
def set_join_code
@join_code = Account::JoinCode.active.find_by(code: Current.membership.join_code)
end
def ensure_join_code_is_valid
unless @join_code&.active?
redirect_to unlink_membership_url(script_name: nil, membership_id: Current.membership.signed_id(purpose: :unlinking))
end
end
def user_params
params.expect(user: [ :name, :avatar ])
end
end
-24
View File
@@ -1,21 +1,7 @@
class UsersController < ApplicationController
require_access_without_a_user only: %i[ new create ]
before_action :set_join_code, :ensure_join_code_is_valid, only: %i[ new create ]
before_action :set_user, only: %i[ show edit update destroy ]
before_action :ensure_permission_to_change_user, only: %i[ update destroy ]
def new
end
def create
@join_code.redeem do
User.create!(user_params.merge(membership: Current.membership))
end
redirect_to root_path
end
def edit
end
@@ -33,16 +19,6 @@ class UsersController < ApplicationController
end
private
def set_join_code
@join_code = Account::JoinCode.active.find_by(code: Current.membership.join_code)
end
def ensure_join_code_is_valid
unless @join_code&.active?
redirect_to unlink_membership_url(script_name: nil, membership_id: Current.membership.signed_id(purpose: :unlinking))
end
end
def set_user
@user = User.active.find(params[:id])
end
@@ -5,10 +5,11 @@
<h1 class="txt-x-large font-weight-black margin-none">
<%= @page_title %>
</h1>
<p class="margin-none-block-start">Enter your name to continue</p>
</header>
<%= form_with scope: "user", url: users_path(membership: params[:membership]), class: "flex flex-column gap txt-medium", data: { controller: "form" } do |form| %>
<%= form_with scope: "user", url: users_joins_path(membership: params[:membership]), class: "flex flex-column gap txt-medium", data: { controller: "form" } do |form| %>
<div class="flex align-center gap">
<label class="flex align-center gap input input--actor">
<%= form.text_field :name, class: "input full-width", autocomplete: "name", placeholder: "Name", autofocus: true, required: true, data: { "1p-ignore": true } %>
+4
View File
@@ -128,6 +128,10 @@ Rails.application.routes.draw do
get "join/:tenant/:code", to: "join_codes#new", as: :join
post "join/:tenant/:code", to: "join_codes#create"
namespace :users do
resources :joins
end
resource :session do
scope module: "sessions" do
resources :transfers
@@ -0,0 +1,32 @@
require "test_helper"
class Users::JoinsControllerTest < ActionDispatch::IntegrationTest
test "new" do
identity = Identity.create!(email_address: "new.user@example.com")
identity.memberships.create(tenant: ApplicationRecord.current_tenant, join_code: Account::JoinCode.sole.code)
sign_in_as identity
get new_users_join_path
assert_response :ok
end
test "new with invalid params" do
identity = Identity.create!(email_address: "new.user@example.com")
membership = identity.memberships.create(tenant: ApplicationRecord.current_tenant, join_code: "PHONY")
sign_in_as identity
get new_users_join_path
assert_redirected_to unlink_membership_url(script_name: nil, membership_id: membership.signed_id(purpose: :unlinking))
end
test "create" do
identity = Identity.create!(email_address: "newart.userbaum@example.com")
identity.memberships.create(tenant: ApplicationRecord.current_tenant, join_code: Account::JoinCode.sole.code)
sign_in_as identity
assert_difference -> { User.count }, +1 do
post users_joins_path, params: { user: { name: "Newart Userbaum" } }
assert_redirected_to root_path
end
end
end
-29
View File
@@ -1,35 +1,6 @@
require "test_helper"
class UsersControllerTest < ActionDispatch::IntegrationTest
test "new" do
identity = Identity.create!(email_address: "new.user@example.com")
identity.memberships.create(tenant: ApplicationRecord.current_tenant, join_code: Account::JoinCode.sole.code)
sign_in_as identity
get new_user_path
assert_response :ok
end
test "new with invalid params" do
identity = Identity.create!(email_address: "new.user@example.com")
membership = identity.memberships.create(tenant: ApplicationRecord.current_tenant, join_code: "PHONY")
sign_in_as identity
get new_user_path
assert_redirected_to unlink_membership_url(script_name: nil, membership_id: membership.signed_id(purpose: :unlinking))
end
test "create" do
identity = Identity.create!(email_address: "newart.userbaum@example.com")
identity.memberships.create(tenant: ApplicationRecord.current_tenant, join_code: Account::JoinCode.sole.code)
sign_in_as identity
assert_difference -> { User.count }, +1 do
post users_path, params: { user: { name: "Newart Userbaum" } }
assert_redirected_to root_path
end
end
test "show" do
sign_in_as :kevin