rails-multitenant-signup-flow 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c6d7c58293b3cf8ebbdc5c2da7dba0bdcc49222586ee38222d7a5b7262761f81
4
+ data.tar.gz: 907accb11cda8e032553fd8b7d3626dc1b4955d01765f897619b134857ed089b
5
+ SHA512:
6
+ metadata.gz: 3ccbfdeb308ab2c30a1585c1908bf856db89e0da10f76d3e009d81e74780b68589ce5034b00aeff50e95d68cbe0f5ebf13c4360da2f5dfe7808a39ee6ee8a032
7
+ data.tar.gz: 72c5d613aacc55df554209a237ce4333e0c60a2e19dea67cbc656547cad64c4ee382107d4c3022cb5145bbf735b66604e3ed20c4deed3c6062e91962c104d014
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,135 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ rails-multitenant-signup-flow (1.0.0)
5
+ activerecord-tenanted (~> 0.6, >= 0.6.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ actionpack (8.1.1)
11
+ actionview (= 8.1.1)
12
+ activesupport (= 8.1.1)
13
+ nokogiri (>= 1.8.5)
14
+ rack (>= 2.2.4)
15
+ rack-session (>= 1.0.1)
16
+ rack-test (>= 0.6.3)
17
+ rails-dom-testing (~> 2.2)
18
+ rails-html-sanitizer (~> 1.6)
19
+ useragent (~> 0.16)
20
+ actionview (8.1.1)
21
+ activesupport (= 8.1.1)
22
+ builder (~> 3.1)
23
+ erubi (~> 1.11)
24
+ rails-dom-testing (~> 2.2)
25
+ rails-html-sanitizer (~> 1.6)
26
+ activemodel (8.1.1)
27
+ activesupport (= 8.1.1)
28
+ activerecord (8.1.1)
29
+ activemodel (= 8.1.1)
30
+ activesupport (= 8.1.1)
31
+ timeout (>= 0.4.0)
32
+ activerecord-tenanted (0.6.0)
33
+ activerecord (>= 8.1.beta)
34
+ railties (>= 8.1.beta)
35
+ zeitwerk
36
+ activesupport (8.1.1)
37
+ base64
38
+ bigdecimal
39
+ concurrent-ruby (~> 1.0, >= 1.3.1)
40
+ connection_pool (>= 2.2.5)
41
+ drb
42
+ i18n (>= 1.6, < 2)
43
+ json
44
+ logger (>= 1.4.2)
45
+ minitest (>= 5.1)
46
+ securerandom (>= 0.3)
47
+ tzinfo (~> 2.0, >= 2.0.5)
48
+ uri (>= 0.13.1)
49
+ base64 (0.3.0)
50
+ bigdecimal (3.3.1)
51
+ builder (3.3.0)
52
+ concurrent-ruby (1.3.5)
53
+ connection_pool (2.5.4)
54
+ crass (1.0.6)
55
+ date (3.5.0)
56
+ drb (2.2.3)
57
+ erb (5.1.3)
58
+ erubi (1.13.1)
59
+ globalid (1.3.0)
60
+ activesupport (>= 6.1)
61
+ i18n (1.14.7)
62
+ concurrent-ruby (~> 1.0)
63
+ io-console (0.8.1)
64
+ irb (1.15.3)
65
+ pp (>= 0.6.0)
66
+ rdoc (>= 4.0.0)
67
+ reline (>= 0.4.2)
68
+ json (2.16.0)
69
+ logger (1.7.0)
70
+ loofah (2.24.1)
71
+ crass (~> 1.0.2)
72
+ nokogiri (>= 1.12.0)
73
+ minitest (5.26.0)
74
+ nokogiri (1.18.10-x86_64-linux-gnu)
75
+ racc (~> 1.4)
76
+ pp (0.6.3)
77
+ prettyprint
78
+ prettyprint (0.2.0)
79
+ psych (5.2.6)
80
+ date
81
+ stringio
82
+ racc (1.8.1)
83
+ rack (3.2.4)
84
+ rack-session (2.1.1)
85
+ base64 (>= 0.1.0)
86
+ rack (>= 3.0.0)
87
+ rack-test (2.2.0)
88
+ rack (>= 1.3)
89
+ rackup (2.2.1)
90
+ rack (>= 3)
91
+ rails-dom-testing (2.3.0)
92
+ activesupport (>= 5.0.0)
93
+ minitest
94
+ nokogiri (>= 1.6)
95
+ rails-html-sanitizer (1.6.2)
96
+ loofah (~> 2.21)
97
+ nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
98
+ railties (8.1.1)
99
+ actionpack (= 8.1.1)
100
+ activesupport (= 8.1.1)
101
+ irb (~> 1.13)
102
+ rackup (>= 1.0.0)
103
+ rake (>= 12.2)
104
+ thor (~> 1.0, >= 1.2.2)
105
+ tsort (>= 0.2)
106
+ zeitwerk (~> 2.6)
107
+ rake (13.3.1)
108
+ rdoc (6.15.1)
109
+ erb
110
+ psych (>= 4.0.0)
111
+ tsort
112
+ reline (0.6.2)
113
+ io-console (~> 0.5)
114
+ securerandom (0.4.1)
115
+ stringio (3.1.7)
116
+ thor (1.4.0)
117
+ timeout (0.4.4)
118
+ tsort (0.2.0)
119
+ tzinfo (2.0.6)
120
+ concurrent-ruby (~> 1.0)
121
+ uri (1.1.1)
122
+ useragent (0.16.11)
123
+ zeitwerk (2.7.3)
124
+
125
+ PLATFORMS
126
+ x86_64-linux-gnu
127
+
128
+ DEPENDENCIES
129
+ globalid (>= 1.0)
130
+ minitest (~> 5.20)
131
+ rails-multitenant-signup-flow!
132
+ railties (>= 7.0)
133
+
134
+ BUNDLED WITH
135
+ 2.7.2
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # Rails Multitenant Signup Flow
2
+
3
+ A Rails generator that installs multi-tenant authentication scaffolding, services, concerns, and configuration based on `activerecord-tenanted`.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```
10
+ gem "rails-multitenant-signup-flow", path: "../rails-multitenant-signup-flow"
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```
16
+ bundle install
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```
22
+ bin/rails generate rails_multitenant_signup_flow:install
23
+ ```
24
+
25
+ Run with `--force` to overwrite existing files.
26
+
27
+ ## After running the generator
28
+
29
+ - Update `config/routes.rb` so your app has a root route, for example:
30
+ ```ruby
31
+ root to: "sign_ups#show"
32
+ ```
33
+ Adjust the controller/action to whatever should serve as your landing page.
34
+ - Start the server with `bin/rails server` and test subdomains locally using [lvh.me](https://lvh.me), which always resolves to `127.0.0.1`. For example, sign in at `http://app.lvh.me:3000` after creating a tenant named `app`.
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "activerecord_tenanted_auth_generator/version"
4
+ require 'activerecord-tenanted'
5
+
6
+ module ActiverecordTenantedAuthGenerator
7
+ end
@@ -0,0 +1,6 @@
1
+ Description:
2
+ Installs authentication controllers and configuration for activerecord-tenanted multi-tenancy.
3
+
4
+ Example:
5
+ bin/rails generate rails_multitenant_signup_flow:install
6
+
@@ -0,0 +1,173 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/base"
4
+ require "fileutils"
5
+
6
+ module RailsMultitenantSignupFlow
7
+ module Generators
8
+ class InstallGenerator < Rails::Generators::Base
9
+ source_root File.expand_path("templates", __dir__)
10
+
11
+ class_option :force, type: :boolean, default: false, desc: "Overwrite existing files"
12
+
13
+ def ensure_authentication_scaffold
14
+ return if authentication_generated?
15
+
16
+ say_status :invoke, "rails generate authentication", :green
17
+ rails_command "generate authentication"
18
+ move_authentication_migrations_to_global
19
+ end
20
+
21
+ def copy_sessions_controller
22
+ template "sessions_controller.rb.tt", "app/controllers/sessions_controller.rb", force: force?
23
+ end
24
+
25
+ def copy_sign_ups_controller
26
+ template "sign_ups_controller.rb.tt", "app/controllers/sign_ups_controller.rb", force: force?
27
+ end
28
+
29
+ def copy_sign_up_view
30
+ template "sign_ups_show.html.erb.tt", "app/views/sign_ups/show.html.erb", force: force?
31
+ end
32
+
33
+ def copy_global_record
34
+ template "global_record.rb.tt", "app/models/global_record.rb", force: force?
35
+ end
36
+
37
+ def copy_host_url_concern
38
+ template "host_url.rb.tt", "app/controllers/concerns/host_url.rb", force: force?
39
+ end
40
+
41
+ def copy_tenant_service
42
+ template "tenant_service.rb.tt", "lib/tenant_service.rb", force: force?
43
+ end
44
+
45
+ def copy_tenant_model
46
+ template "tenant.rb.tt", "app/models/tenant.rb", force: force?
47
+ end
48
+
49
+ def copy_user_model
50
+ template "user.rb.tt", "app/models/user.rb", force: force?
51
+ end
52
+
53
+ def copy_session_model
54
+ template "session.rb.tt", "app/models/session.rb", force: force?
55
+ end
56
+
57
+ def configure_application_record
58
+ path = "app/models/application_record.rb"
59
+ if File.exist?(path)
60
+ ensure_tenanted_in_application_record(path)
61
+ else
62
+ say_status :missing, path, :yellow
63
+ create_default_application_record(path)
64
+ end
65
+ end
66
+
67
+ def configure_database
68
+ template "database.yml.tt", "config/database.yml", force: force?
69
+ end
70
+
71
+ def ensure_sign_up_route
72
+ routes_path = "config/routes.rb"
73
+ return unless File.exist?(routes_path)
74
+
75
+ content = File.read(routes_path)
76
+ return if content.include?("resource :sign_up")
77
+
78
+ route "resource :sign_up, only: [:show, :create]"
79
+ end
80
+
81
+ def generate_tenant_migrations
82
+ say_status :invoke, "rails generate migration CreateTenants", :green
83
+ rails_command "generate migration CreateTenants name:string --database=global"
84
+
85
+ say_status :invoke, "rails generate migration AddTenantToUsers", :green
86
+ rails_command "generate migration AddTenantToUsers tenant:references --database=global"
87
+
88
+ modify_add_tenant_to_users_migration
89
+ end
90
+
91
+ private
92
+
93
+ def authentication_generated?
94
+ File.exist?("app/models/user.rb") && File.read("app/models/user.rb").match?(/has_secure_password/)
95
+ rescue Errno::ENOENT
96
+ false
97
+ end
98
+
99
+ def ensure_tenanted_in_application_record(path)
100
+ contents = File.read(path)
101
+ return if contents.include?("tenanted")
102
+
103
+ if contents.match?(/primary_abstract_class/)
104
+ gsub_file path, /primary_abstract_class\s*\n/, "primary_abstract_class\n tenanted\n"
105
+ else
106
+ inject_into_class path, "ApplicationRecord", " tenanted\n"
107
+ end
108
+ end
109
+
110
+ def create_default_application_record(path)
111
+ create_file path, <<~RUBY, force: force?
112
+ class ApplicationRecord < ActiveRecord::Base
113
+ primary_abstract_class
114
+ tenanted
115
+ end
116
+ RUBY
117
+ end
118
+
119
+ def force?
120
+ options[:force]
121
+ end
122
+
123
+ def move_authentication_migrations_to_global
124
+ Dir.glob("db/migrate/*_create_users.rb").each do |file|
125
+ move_migration file
126
+ end
127
+
128
+ Dir.glob("db/migrate/*_create_sessions.rb").each do |file|
129
+ move_migration file
130
+ end
131
+ end
132
+
133
+ def move_migration(file)
134
+ destination = file.gsub("db/migrate", "db/global_migrate")
135
+ FileUtils.mkdir_p("db/global_migrate")
136
+ FileUtils.mv(file, destination)
137
+ say_status :move, "#{file} -> #{destination}", :green
138
+ end
139
+
140
+ def modify_add_tenant_to_users_migration
141
+ migration_file = Dir.glob("db/global_migrate/*_add_tenant_to_users.rb").max_by { |f| File.mtime(f) }
142
+ return unless migration_file
143
+
144
+ content = File.read(migration_file)
145
+
146
+ new_content = content.gsub(
147
+ /def change\s*\n\s*add_reference :users, :tenant.*?\n\s*end/m,
148
+ <<~RUBY.strip
149
+ def change
150
+ add_reference :users, :tenant, null: true, foreign_key: true
151
+
152
+ # Create a default tenant using SQL
153
+ execute <<-SQL
154
+ INSERT INTO tenants (name, created_at, updated_at) VALUES ('default', datetime('now'), datetime('now'))
155
+ SQL
156
+
157
+ # Assign all existing users to the default tenant (id=1 since it's the first)
158
+ execute <<-SQL
159
+ UPDATE users SET tenant_id = 1
160
+ SQL
161
+
162
+ # Make the column NOT NULL
163
+ change_column_null :users, :tenant_id, false
164
+ end
165
+ RUBY
166
+ )
167
+
168
+ File.write(migration_file, new_content)
169
+ say_status :modify, migration_file, :yellow
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,42 @@
1
+ default: &default
2
+ adapter: sqlite3
3
+ pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
4
+ timeout: 5000
5
+
6
+ development:
7
+ primary:
8
+ <<: *default
9
+ database: storage/development/%{tenant}/development.sqlite3
10
+ tenanted: true
11
+ global:
12
+ <<: *default
13
+ database: storage/development/global.sqlite3
14
+ migrations_paths: db/global_migrate
15
+
16
+ test:
17
+ primary:
18
+ <<: *default
19
+ database: storage/test/%{tenant}/test.sqlite3
20
+ tenanted: true
21
+ global:
22
+ <<: *default
23
+ database: storage/test/global.sqlite3
24
+ migrations_paths: db/global_migrate
25
+
26
+ production:
27
+ primary:
28
+ <<: *default
29
+ database: storage/production/%{tenant}/production.sqlite3
30
+ tenanted: true
31
+ cache:
32
+ <<: *default
33
+ database: storage/production_cache.sqlite3
34
+ migrations_paths: db/cache_migrate
35
+ queue:
36
+ <<: *default
37
+ database: storage/production_queue.sqlite3
38
+ migrations_paths: db/queue_migrate
39
+ cable:
40
+ <<: *default
41
+ database: storage/production_cable.sqlite3
42
+ migrations_paths: db/cable_migrate
@@ -0,0 +1,4 @@
1
+ class GlobalRecord < ActiveRecord::Base
2
+ self.abstract_class = true
3
+ connects_to database: { writing: :global, reading: :global }
4
+ end
@@ -0,0 +1,20 @@
1
+ module HostUrl
2
+ extend ActiveSupport::Concern
3
+
4
+ private
5
+ def host_url(tenant_name: nil, root: false)
6
+ host = if root
7
+ request.domain
8
+ elsif TenantService.tenant_subdomain?(request)
9
+ request.host
10
+ elsif Current.user
11
+ "#{Current.user&.tenant&.name}.#{request.host}"
12
+ elsif tenant_name.present?
13
+ "#{tenant_name}.#{request.host}"
14
+ else
15
+ request.host
16
+ end
17
+ host += ":#{request.port}" unless [80, 443].include?(request.port)
18
+ host
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ class Session < GlobalRecord
2
+ belongs_to :user
3
+ end
@@ -0,0 +1,31 @@
1
+ class SessionsController < ApplicationController
2
+ include HostUrl
3
+
4
+ allow_unauthenticated_access only: %i[new create]
5
+ rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_path, alert: "Try again later." }
6
+ before_action :redirect_if_authenticated, only: %i[new create]
7
+
8
+ def new
9
+ end
10
+
11
+ def create
12
+ if (user = User.authenticate_by(params.permit(:email_address, :password)))
13
+ start_new_session_for user
14
+
15
+ redirect_to root_url(host: host_url(tenant_name: user.tenant.name)), allow_other_host: true
16
+ else
17
+ redirect_to new_session_path, alert: "Try another email address or password."
18
+ end
19
+ end
20
+
21
+ def destroy
22
+ terminate_session
23
+ redirect_to root_url(host: host_url(root: true)), allow_other_host: true
24
+ end
25
+
26
+ private
27
+
28
+ def redirect_if_authenticated
29
+ redirect_to root_path if authenticated?
30
+ end
31
+ end
@@ -0,0 +1,72 @@
1
+ class SignUpsController < ApplicationController
2
+ include HostUrl
3
+ allow_unauthenticated_access
4
+ rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to sign_up_path, alert: "Try again later." }
5
+
6
+ before_action :redirect_if_on_subdomain, only: :show
7
+ before_action :validate_tenant_subdomain, only: :create
8
+ before_action :validate_tenant_availability, only: :create
9
+
10
+ def show
11
+ @user = User.new
12
+ end
13
+
14
+ def create
15
+ tenant_name = sign_up_params[:tenant_name]
16
+
17
+ @user = User.new(sign_up_params.except(:tenant_name))
18
+
19
+ User.transaction do
20
+ @user.tenant = if TenantService.tenant_subdomain?(request)
21
+ Tenant.find_by!(name: TenantService.current_tenant_name(request))
22
+ elsif tenant_name.present?
23
+ TenantService.create!(tenant_name)
24
+ end
25
+
26
+ if @user.save
27
+ start_new_session_for(@user)
28
+ redirect_to root_url(host: host_url(tenant_name: @user.tenant.name)), allow_other_host: true
29
+ else
30
+ render :show, status: :unprocessable_entity
31
+ end
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def sign_up_params
38
+ params.expect(user: %i[email_address password password_confirmation tenant_name])
39
+ end
40
+
41
+ def validate_tenant_availability
42
+ return unless sign_up_params[:tenant_name].present?
43
+
44
+ tenant_name = sign_up_params[:tenant_name]
45
+
46
+ if TenantService.tenant_exists?(tenant_name) && !TenantService.tenant_subdomain?(request)
47
+ @user = User.new(sign_up_params.except(:tenant_name))
48
+ flash.now[:alert] = "That tenant already exists. Please choose another name."
49
+ render :show, status: :unprocessable_entity
50
+ end
51
+ end
52
+
53
+ def validate_tenant_subdomain
54
+ if TenantService.tenant_subdomain?(request)
55
+ tenant_name = TenantService.current_tenant_name(request)
56
+ unless TenantService.tenant_exists?(tenant_name)
57
+ raise ActionController::BadRequest, "Invalid tenant subdomain"
58
+ end
59
+
60
+ tenant_name_to_validate = sign_up_params[:tenant_name]
61
+ if tenant_name_to_validate.present? && tenant_name_to_validate != tenant_name
62
+ raise ActionController::BadRequest, "Tenant name does not match subdomain"
63
+ end
64
+ elsif sign_up_params[:tenant_name].blank?
65
+ raise ActionController::BadRequest, "Tenant name is required"
66
+ end
67
+ end
68
+
69
+ def redirect_if_on_subdomain
70
+ redirect_to sign_up_url(host: host_url(root: true)), allow_other_host: true if TenantService.tenant_subdomain?(request)
71
+ end
72
+ end
@@ -0,0 +1,41 @@
1
+ <h1>Sign up</h1>
2
+
3
+ <%%= form_with model: @user, url: sign_up_path do |form| %>
4
+ <%% if form.object.errors.any? %>
5
+ <div class="form-errors">
6
+ <h2><%%= pluralize(form.object.errors.count, "error") %> prohibited this account from being created:</h2>
7
+ <ul>
8
+ <%% form.object.errors.each do |error| %>
9
+ <li><%%= error.full_message %></li>
10
+ <%% end %>
11
+ </ul>
12
+ </div>
13
+ <%% end %>
14
+
15
+ <div class="form-field">
16
+ <%%= form.label :email_address, "Email address" %><br>
17
+ <%%= form.email_field :email_address, required: true, autofocus: true, autocomplete: "email" %>
18
+ </div>
19
+
20
+ <%% unless TenantService.tenant_subdomain?(request) %>
21
+ <div class="form-field">
22
+ <%%= form.label :tenant_name, "Tenant name" %><br>
23
+ <%%= form.text_field :tenant_name, required: true, autocomplete: "organization", placeholder: "example" %>
24
+ <p class="help-text">Use lowercase letters, numbers, and hyphens. This becomes your tenant subdomain.</p>
25
+ </div>
26
+ <%% end %>
27
+
28
+ <div class="form-field">
29
+ <%%= form.label :password, "Password" %><br>
30
+ <%%= form.password_field :password, required: true, autocomplete: "new-password", maxlength: 72 %>
31
+ </div>
32
+
33
+ <div class="form-field">
34
+ <%%= form.label :password_confirmation, "Confirm password" %><br>
35
+ <%%= form.password_field :password_confirmation, required: true, autocomplete: "new-password", maxlength: 72 %>
36
+ </div>
37
+
38
+ <div class="form-actions">
39
+ <%%= form.submit "Sign up" %>
40
+ </div>
41
+ <%% end %>
@@ -0,0 +1,14 @@
1
+ class Tenant < GlobalRecord
2
+ has_many :users
3
+
4
+ validates :name, presence: true, uniqueness: { case_sensitive: false }, length: { in: 1..63 }
5
+ validates :name, format: { with: /\A[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\z/, message: "must be a valid subdomain (lowercase letters, numbers, and hyphens only, no leading/trailing hyphens)" }
6
+
7
+ before_validation :downcase_name
8
+
9
+ private
10
+
11
+ def downcase_name
12
+ self.name = name.downcase if name.present?
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ class TenantService
2
+ def self.create!(tenant_name)
3
+ Tenant.transaction do
4
+ tenant = Tenant.create!(name: tenant_name)
5
+ ApplicationRecord.create_tenant(tenant_name)
6
+ tenant
7
+ end
8
+ end
9
+
10
+ def self.tenant_exists?(tenant_name)
11
+ Tenant.exists?(name: tenant_name)
12
+ end
13
+
14
+ def self.tenant_subdomain?(request)
15
+ request.subdomain.present? && request.subdomain != "www"
16
+ end
17
+
18
+ def self.current_tenant_name(request)
19
+ request.subdomain if tenant_subdomain?(request)
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ class User < GlobalRecord
2
+ has_secure_password
3
+ has_many :sessions, dependent: :destroy
4
+ belongs_to :tenant
5
+
6
+ validates :email_address, presence: true, uniqueness: true
7
+ normalizes :email_address, with: ->(e) { e.strip.downcase }
8
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsMultitenantSignupFlow
4
+ VERSION = "1.0.0"
5
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "rails_multitenant_signup_flow/version"
4
+ require "activerecord-tenanted"
5
+
6
+ module RailsMultitenantSignupFlow
7
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-multitenant-signup-flow
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - WToa
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activerecord-tenanted
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '0.6'
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: 0.6.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - "~>"
27
+ - !ruby/object:Gem::Version
28
+ version: '0.6'
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 0.6.0
32
+ - !ruby/object:Gem::Dependency
33
+ name: minitest
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - "~>"
37
+ - !ruby/object:Gem::Version
38
+ version: '5.20'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - "~>"
44
+ - !ruby/object:Gem::Version
45
+ version: '5.20'
46
+ - !ruby/object:Gem::Dependency
47
+ name: railties
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '7.0'
53
+ type: :development
54
+ prerelease: false
55
+ version_requirements: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '7.0'
60
+ - !ruby/object:Gem::Dependency
61
+ name: globalid
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '1.0'
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '1.0'
74
+ description: Installs controllers, services, and configuration to enable multi-tenant
75
+ authentication using activerecord-tenanted.
76
+ email:
77
+ - will@wtoa.dev
78
+ executables: []
79
+ extensions: []
80
+ extra_rdoc_files: []
81
+ files:
82
+ - Gemfile
83
+ - Gemfile.lock
84
+ - README.md
85
+ - lib/activerecord_tenanted_auth_generator.rb
86
+ - lib/generators/rails_multitenant_signup_flow/install/USAGE
87
+ - lib/generators/rails_multitenant_signup_flow/install/install_generator.rb
88
+ - lib/generators/rails_multitenant_signup_flow/install/templates/database.yml.tt
89
+ - lib/generators/rails_multitenant_signup_flow/install/templates/global_record.rb.tt
90
+ - lib/generators/rails_multitenant_signup_flow/install/templates/host_url.rb.tt
91
+ - lib/generators/rails_multitenant_signup_flow/install/templates/session.rb.tt
92
+ - lib/generators/rails_multitenant_signup_flow/install/templates/sessions_controller.rb.tt
93
+ - lib/generators/rails_multitenant_signup_flow/install/templates/sign_ups_controller.rb.tt
94
+ - lib/generators/rails_multitenant_signup_flow/install/templates/sign_ups_show.html.erb.tt
95
+ - lib/generators/rails_multitenant_signup_flow/install/templates/tenant.rb.tt
96
+ - lib/generators/rails_multitenant_signup_flow/install/templates/tenant_service.rb.tt
97
+ - lib/generators/rails_multitenant_signup_flow/install/templates/user.rb.tt
98
+ - lib/rails_multitenant_signup_flow.rb
99
+ - lib/rails_multitenant_signup_flow/version.rb
100
+ homepage: https://github.com/WToa/rails-multitenant-signup-flow
101
+ licenses:
102
+ - MIT
103
+ metadata:
104
+ homepage_uri: https://github.com/WToa/rails-multitenant-signup-flow
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 3.0.0
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubygems_version: 3.6.9
120
+ specification_version: 4
121
+ summary: Generators for configuring a Rails multi-tenant signup flow with activerecord-tenanted.
122
+ test_files: []