From ee60e8dd01f5451b490e9953a32fb149e7f352dd Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Mon, 16 Jun 2025 17:10:01 -0400 Subject: [PATCH] Signup::AccountsController suppports signing up with a new identity --- app/controllers/concerns/authentication.rb | 1 + app/controllers/signup/accounts_controller.rb | 27 +++++++++ app/views/signup/accounts/new.html.erb | 58 +++++++++++++++++++ config/initializers/tenanting.rb | 13 ++++- config/routes.rb | 5 ++ .../signup/accounts_controller_test.rb | 39 +++++++++++++ 6 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 app/controllers/signup/accounts_controller.rb create mode 100644 app/views/signup/accounts/new.html.erb create mode 100644 test/controllers/signup/accounts_controller_test.rb diff --git a/app/controllers/concerns/authentication.rb b/app/controllers/concerns/authentication.rb index d47dc44d2..dc75fb777 100644 --- a/app/controllers/concerns/authentication.rb +++ b/app/controllers/concerns/authentication.rb @@ -19,6 +19,7 @@ module Authentication end def require_untenanted_access(**options) + skip_before_action :set_current_account, **options skip_before_action :require_authentication, **options before_action :redirect_tenanted_request, **options end diff --git a/app/controllers/signup/accounts_controller.rb b/app/controllers/signup/accounts_controller.rb new file mode 100644 index 000000000..e722684ea --- /dev/null +++ b/app/controllers/signup/accounts_controller.rb @@ -0,0 +1,27 @@ +class Signup::AccountsController < ApplicationController + require_untenanted_access + + def new + @signup = Signup.new + end + + def create + @signup = Signup.new(signup_params) + + if @signup.process + redirect_to_account(@signup.account) + else + render :new, status: :unprocessable_entity + end + end + + private + def signup_params + params.require(:signup).permit(:full_name, :email_address, :password, :company_name) + end + + def redirect_to_account(account) + redirect_to account.signal_account.owner.remote_login_url(proceed_to: root_path), + allow_other_host: true + end +end diff --git a/app/views/signup/accounts/new.html.erb b/app/views/signup/accounts/new.html.erb new file mode 100644 index 000000000..9f69eba4b --- /dev/null +++ b/app/views/signup/accounts/new.html.erb @@ -0,0 +1,58 @@ +<% @page_title = "Sign up for Fizzy" %> + +
" style="--panel-size: 65ch;"> +

Fizzy

+

Create your account

+ + <%= form_with model: @signup, url: signup_accounts_path, scope: "signup", class: "flex flex-column gap txt-large", data: { turbo: false } do |form| %> +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ + <% if @signup.errors.any? %> +
+
    + <% @signup.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+ <% end %> + + + <% end %> + + +
diff --git a/config/initializers/tenanting.rb b/config/initializers/tenanting.rb index 78e5d8e05..ce4193330 100644 --- a/config/initializers/tenanting.rb +++ b/config/initializers/tenanting.rb @@ -2,10 +2,17 @@ Rails.application.config.after_initialize do # in production and staging, we're using a two-level subdomain like "tenant.fizzy.37signals.com". # in development and beta it's only a single-level subdomain. Rails.application.config.active_record_tenanted.tenant_resolver = ->(request) do - next nil if request.path == "/up" - tld_length = [ "37signals.com", "37signals-staging.com" ].include?(request.domain) ? 2 : 1 - request.subdomain(tld_length).presence || "return-404" # this is a quick fix for now + + if request.path == "/up" + nil + elsif subdomain = request.subdomain(tld_length).presence + subdomain + elsif optional = request.path =~ %r{^/signup\b} + nil + else + "return-404" # this is a quick fix for now + end end end diff --git a/config/routes.rb b/config/routes.rb index 7cf104da4..ad780b0da 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -88,6 +88,11 @@ Rails.application.routes.draw do get "launchpad", to: "sessions/launchpad#show" end + namespace :signup do + get "/" => "accounts#new" + resources :accounts, only: %i[ new create ] + end + resources :users do scope module: :users do resource :avatar diff --git a/test/controllers/signup/accounts_controller_test.rb b/test/controllers/signup/accounts_controller_test.rb new file mode 100644 index 000000000..f7c2a6ad7 --- /dev/null +++ b/test/controllers/signup/accounts_controller_test.rb @@ -0,0 +1,39 @@ +require "test_helper" + +class Signup::AccountsControllerTest < ActionDispatch::IntegrationTest + test "new at a tenanted domain" do + get new_signup_account_url + + assert_redirected_to root_url + end + + test "new at an untenanted domain" do + integration_session.host = "example.com" # no subdomain + + get new_signup_account_url + + assert_response :success + end + + test "create with invalid params" do + integration_session.host = "example.com" # no subdomain + + post signup_accounts_url, params: { signup: { full_name: "Jim", email_address: "jim@example.com", password: "", company_name: "" } } + + assert_response :unprocessable_entity + assert_select "div.alert--error", text: /you need to choose a password/i + end + + test "create for a new " do + integration_session.host = "example.com" # no subdomain + + assert_difference -> { SignalId::Identity.count }, +1 do + assert_difference -> { SignalId::Account.count }, +1 do + post signup_accounts_url, params: { signup: { full_name: "Jim", email_address: "jim@example.com", password: SecureRandom.hex(12), company_name: "signup-accounts-controller-test-1" } } + end + end + + signal_account = SignalId::Account.last + assert_redirected_to(/#{signal_account.login_url}/) + end +end