devise_token_auth_multi_email 0.9.4 → 0.9.5
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 +4 -4
- data/README.md +3 -0
- data/Rakefile +4 -8
- data/app/controllers/devise_token_auth/concerns/resource_finder.rb +2 -9
- data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +35 -5
- data/app/controllers/devise_token_auth/registrations_controller.rb +24 -18
- data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +6 -3
- data/lib/devise_token_auth/engine.rb +40 -1
- data/lib/devise_token_auth/version.rb +1 -1
- data/test/controllers/devise_token_auth/confirmations_controller_test.rb +4 -4
- data/test/controllers/devise_token_auth/multi_email_coexistence_test.rb +130 -0
- data/test/controllers/devise_token_auth/multi_email_confirmations_controller_test.rb +210 -0
- data/test/controllers/devise_token_auth/multi_email_passwords_controller_test.rb +247 -0
- data/test/controllers/devise_token_auth/multi_email_registrations_controller_test.rb +137 -0
- data/test/controllers/devise_token_auth/multi_email_sessions_controller_test.rb +191 -0
- data/test/controllers/devise_token_auth/multi_email_token_validations_controller_test.rb +140 -0
- data/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +5 -4
- data/test/controllers/devise_token_auth/standard_user_registrations_controller_test.rb +165 -0
- data/test/coverage/assets/0.13.2/colorbox/loading.gif +0 -0
- data/test/coverage/assets/0.13.2/loading.gif +0 -0
- data/test/dummy/app/active_record/multi_email_user.rb +45 -0
- data/test/dummy/app/active_record/multi_email_user_email.rb +21 -0
- data/test/dummy/config/application.rb +6 -1
- data/test/dummy/config/initializers/omniauth.rb +15 -1
- data/test/dummy/config/routes.rb +8 -0
- data/test/dummy/db/migrate/20260401000001_devise_token_auth_create_multi_email_users.rb +49 -0
- data/test/dummy/db/migrate/20260401000002_devise_token_auth_create_multi_email_user_emails.rb +29 -0
- data/test/dummy/db/schema.rb +81 -41
- data/test/dummy/db/test.sqlite3-shm +0 -0
- data/test/dummy/tmp/generators/app/controllers/application_controller.rb +6 -0
- data/test/dummy/tmp/generators/app/models/{user.rb → azpire/v1/human_resource/user.rb} +1 -1
- data/test/dummy/tmp/generators/config/initializers/devise_token_auth.rb +11 -5
- data/test/dummy/tmp/generators/db/migrate/{20210305040222_devise_token_auth_create_users.rb → 20260408021432_devise_token_auth_create_azpire_v1_human_resource_users.rb} +7 -7
- data/test/factories/users.rb +1 -0
- data/test/lib/devise_token_auth/controllers/helpers_test.rb +402 -0
- data/test/lib/devise_token_auth/token_factory_test.rb +18 -18
- data/test/lib/generators/devise_token_auth/install_generator_test.rb +60 -0
- data/test/lib/generators/devise_token_auth/install_generator_with_namespace_test.rb +1 -1
- data/test/lib/generators/devise_token_auth/install_mongoid_generator_test.rb +218 -0
- data/test/models/multi_email_user_email_test.rb +95 -0
- data/test/models/multi_email_user_test.rb +225 -0
- data/test/test_helper.rb +21 -11
- data/test/validators/devise_token_auth_email_validator_test.rb +114 -0
- metadata +58 -27
- data/test/dummy/tmp/generators/app/models/mang.rb +0 -9
- data/test/dummy/tmp/generators/config/routes.rb +0 -9
- data/test/dummy/tmp/generators/db/migrate/20210305040222_devise_token_auth_create_mangs.rb +0 -49
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
|
|
5
|
+
# Tests that verify the TokenValidationsController works correctly with a
|
|
6
|
+
# MultiEmailUser — a model that uses :multi_email_authenticatable from the
|
|
7
|
+
# devise-multi_email gem.
|
|
8
|
+
#
|
|
9
|
+
# Token validation uses the uid / access-token / client headers; the uid is the
|
|
10
|
+
# primary email address, which is synced to the uid column by the sync_uid
|
|
11
|
+
# before_save callback. No multi-email-specific lookup is needed here because
|
|
12
|
+
# the token is looked up by uid (a real column), so this test primarily
|
|
13
|
+
# confirms that the standard flow works end-to-end for multi-email users.
|
|
14
|
+
#
|
|
15
|
+
# These tests are ActiveRecord-only — the MultiEmailUser model and its route
|
|
16
|
+
# are not available in Mongoid runs.
|
|
17
|
+
return unless DEVISE_TOKEN_AUTH_ORM == :active_record
|
|
18
|
+
|
|
19
|
+
class MultiEmailTokenValidationsControllerTest < ActionDispatch::IntegrationTest
|
|
20
|
+
describe 'MultiEmailUser token validation' do
|
|
21
|
+
def registration_params(email: nil)
|
|
22
|
+
{
|
|
23
|
+
email: email || Faker::Internet.unique.email,
|
|
24
|
+
password: 'secret123',
|
|
25
|
+
password_confirmation: 'secret123',
|
|
26
|
+
confirm_success_url: Faker::Internet.url
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Register a user, confirm it, and sign in. Returns [user, auth_headers].
|
|
31
|
+
def sign_in_confirmed_user
|
|
32
|
+
email = Faker::Internet.unique.email
|
|
33
|
+
|
|
34
|
+
post '/multi_email_auth', params: registration_params(email: email)
|
|
35
|
+
assert_equal 200, response.status, "Registration failed: #{response.body}"
|
|
36
|
+
user = assigns(:resource)
|
|
37
|
+
user.confirm
|
|
38
|
+
|
|
39
|
+
post '/multi_email_auth/sign_in',
|
|
40
|
+
params: { email: email, password: 'secret123' }
|
|
41
|
+
assert_equal 200, response.status, "Sign-in failed: #{response.body}"
|
|
42
|
+
|
|
43
|
+
auth_headers = {
|
|
44
|
+
'access-token' => response.headers['access-token'],
|
|
45
|
+
'client' => response.headers['client'],
|
|
46
|
+
'uid' => response.headers['uid'],
|
|
47
|
+
'token-type' => response.headers['token-type']
|
|
48
|
+
}
|
|
49
|
+
[user, auth_headers]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
before do
|
|
53
|
+
@user, @auth_headers = sign_in_confirmed_user
|
|
54
|
+
@client_id = @auth_headers['client']
|
|
55
|
+
|
|
56
|
+
# Age the token so the request is not treated as a batch request.
|
|
57
|
+
age_token(@user, @client_id)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# -----------------------------------------------------------------------
|
|
61
|
+
# Valid token
|
|
62
|
+
# -----------------------------------------------------------------------
|
|
63
|
+
describe 'valid token' do
|
|
64
|
+
before do
|
|
65
|
+
get '/multi_email_auth/validate_token', headers: @auth_headers
|
|
66
|
+
@data = JSON.parse(response.body)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
test 'request is successful' do
|
|
70
|
+
assert_equal 200, response.status
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
test 'response includes user data' do
|
|
74
|
+
assert @data['data']
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
test 'response data includes the correct email' do
|
|
78
|
+
assert @data['data']['email']
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# -----------------------------------------------------------------------
|
|
83
|
+
# Invalid access-token
|
|
84
|
+
# -----------------------------------------------------------------------
|
|
85
|
+
describe 'invalid access-token' do
|
|
86
|
+
before do
|
|
87
|
+
bad_headers = @auth_headers.merge('access-token' => 'this-is-wrong')
|
|
88
|
+
get '/multi_email_auth/validate_token', headers: bad_headers
|
|
89
|
+
@data = JSON.parse(response.body)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
test 'request fails' do
|
|
93
|
+
assert_equal 401, response.status
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
test 'response contains errors' do
|
|
97
|
+
assert @data['errors']
|
|
98
|
+
assert_equal [I18n.t('devise_token_auth.token_validations.invalid')],
|
|
99
|
+
@data['errors']
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# -----------------------------------------------------------------------
|
|
104
|
+
# Missing auth headers
|
|
105
|
+
# -----------------------------------------------------------------------
|
|
106
|
+
describe 'missing auth headers' do
|
|
107
|
+
before do
|
|
108
|
+
get '/multi_email_auth/validate_token'
|
|
109
|
+
@data = JSON.parse(response.body)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
test 'request fails' do
|
|
113
|
+
assert_equal 401, response.status
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
test 'response contains errors' do
|
|
117
|
+
assert @data['errors']
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# -----------------------------------------------------------------------
|
|
122
|
+
# Expired token
|
|
123
|
+
# -----------------------------------------------------------------------
|
|
124
|
+
describe 'expired token' do
|
|
125
|
+
before do
|
|
126
|
+
expire_token(@user, @client_id)
|
|
127
|
+
get '/multi_email_auth/validate_token', headers: @auth_headers
|
|
128
|
+
@data = JSON.parse(response.body)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
test 'request fails' do
|
|
132
|
+
assert_equal 401, response.status
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
test 'response contains errors' do
|
|
136
|
+
assert @data['errors']
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -16,9 +16,11 @@ class OmniauthTest < ActionDispatch::IntegrationTest
|
|
|
16
16
|
@redirect_url = 'https://ng-token-auth.dev/'
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
# Suggested by GPT-5.2 as a more tolerant alternative to the above regex, which was brittle and failed when the JSON data contained certain characters.
|
|
19
20
|
def get_parsed_data_json
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
m = response.body.match(/var\s+data\s*=\s*JSON\.parse\(decodeURIComponent\(['"](.+?)['"]\)\)/m)
|
|
22
|
+
raise "Could not find encoded data payload in response body" unless m
|
|
23
|
+
JSON.parse(CGI.unescape(m[1]))
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
describe 'success callback' do
|
|
@@ -79,8 +81,7 @@ class OmniauthTest < ActionDispatch::IntegrationTest
|
|
|
79
81
|
|
|
80
82
|
test 'should be redirected via valid url' do
|
|
81
83
|
get_success
|
|
82
|
-
assert_equal '
|
|
83
|
-
request.original_url
|
|
84
|
+
assert_equal '/auth/facebook/callback', URI.parse(request.original_url).path
|
|
84
85
|
end
|
|
85
86
|
|
|
86
87
|
describe 'with default user model' do
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
|
|
5
|
+
# Tests that verify devise_token_auth works correctly with a **standard** model —
|
|
6
|
+
# one that does NOT use devise-multi_email (i.e. does NOT have multi_email_association).
|
|
7
|
+
#
|
|
8
|
+
# Standard models get the email uniqueness validation directly from
|
|
9
|
+
# DeviseTokenAuth::Concerns::UserOmniauthCallbacks, regardless of whether the
|
|
10
|
+
# devise-multi_email gem is loaded. These tests confirm:
|
|
11
|
+
# • Basic registration, authentication, and account management work.
|
|
12
|
+
# • Duplicate email registrations are rejected at the model level (no DB
|
|
13
|
+
# constraint exception reaching PostgreSQL that would abort the transaction).
|
|
14
|
+
# • An OAuth user's email can be re-used for an email-provider registration
|
|
15
|
+
# because uniqueness is scoped to provider.
|
|
16
|
+
#
|
|
17
|
+
# These tests are ActiveRecord-specific because they validate AR-level validators
|
|
18
|
+
# and the MultiEmailUser ActiveRecord model (used for contrast tests).
|
|
19
|
+
return unless DEVISE_TOKEN_AUTH_ORM == :active_record
|
|
20
|
+
|
|
21
|
+
class StandardUserRegistrationsControllerTest < ActionDispatch::IntegrationTest
|
|
22
|
+
describe 'Standard User (without multi_email_authenticatable)' do
|
|
23
|
+
def registration_params(email: nil)
|
|
24
|
+
{
|
|
25
|
+
email: email || Faker::Internet.unique.email,
|
|
26
|
+
password: 'secret123',
|
|
27
|
+
password_confirmation: 'secret123',
|
|
28
|
+
confirm_success_url: Faker::Internet.url
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# -----------------------------------------------------------------------
|
|
33
|
+
# Uniqueness validation lives in the concern for standard models
|
|
34
|
+
# -----------------------------------------------------------------------
|
|
35
|
+
describe 'email uniqueness' do
|
|
36
|
+
test 'validates uniqueness at the model level — not at the DB' do
|
|
37
|
+
# The concern (UserOmniauthCallbacks) adds this validation for standard
|
|
38
|
+
# models so the check happens before the INSERT, keeping PostgreSQL
|
|
39
|
+
# transactions clean.
|
|
40
|
+
assert User.validators_on(:email).any? { |v|
|
|
41
|
+
v.is_a?(ActiveRecord::Validations::UniquenessValidator)
|
|
42
|
+
}, 'Expected a UniquenessValidator on User#email'
|
|
43
|
+
|
|
44
|
+
assert Mang.validators_on(:email).any? { |v|
|
|
45
|
+
v.is_a?(ActiveRecord::Validations::UniquenessValidator)
|
|
46
|
+
}, 'Expected a UniquenessValidator on Mang#email'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
test 'multi_email model does NOT carry the concern uniqueness validator' do
|
|
50
|
+
# MultiEmailUser uses :multi_email_authenticatable so it has
|
|
51
|
+
# multi_email_association — the concern skips adding the uniqueness
|
|
52
|
+
# validator (the emails table enforces uniqueness instead).
|
|
53
|
+
refute MultiEmailUser.validators_on(:email).any? { |v|
|
|
54
|
+
v.is_a?(ActiveRecord::Validations::UniquenessValidator)
|
|
55
|
+
}, 'Expected NO UniquenessValidator on MultiEmailUser#email'
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# -----------------------------------------------------------------------
|
|
60
|
+
# Successful registration
|
|
61
|
+
# -----------------------------------------------------------------------
|
|
62
|
+
describe 'successful registration' do
|
|
63
|
+
before do
|
|
64
|
+
post '/auth', params: registration_params
|
|
65
|
+
@resource = assigns(:resource)
|
|
66
|
+
@data = JSON.parse(response.body)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
test 'request is successful' do
|
|
70
|
+
assert_equal 200, response.status
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
test 'user is persisted' do
|
|
74
|
+
assert @resource.id
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
test 'resource is a standard User' do
|
|
78
|
+
assert_equal User, @resource.class
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
test 'response includes email' do
|
|
82
|
+
assert @data['data']['email']
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# -----------------------------------------------------------------------
|
|
87
|
+
# Duplicate email registration is rejected at the model level
|
|
88
|
+
# -----------------------------------------------------------------------
|
|
89
|
+
describe 'duplicate email registration' do
|
|
90
|
+
before do
|
|
91
|
+
@email = Faker::Internet.unique.email
|
|
92
|
+
create(:user, email: @email, provider: 'email').tap(&:confirm)
|
|
93
|
+
|
|
94
|
+
post '/auth', params: registration_params(email: @email)
|
|
95
|
+
@data = JSON.parse(response.body)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
test 'request is rejected' do
|
|
99
|
+
assert_equal 422, response.status
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
test 'errors mention email taken' do
|
|
103
|
+
assert_not_empty @data['errors']
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# -----------------------------------------------------------------------
|
|
108
|
+
# OAuth user + same email re-used for email-provider registration
|
|
109
|
+
# (uniqueness is scoped to provider)
|
|
110
|
+
# -----------------------------------------------------------------------
|
|
111
|
+
describe 'email re-use across providers' do
|
|
112
|
+
before do
|
|
113
|
+
@oauth_user = create(:user, :facebook, :confirmed)
|
|
114
|
+
|
|
115
|
+
post '/auth',
|
|
116
|
+
params: registration_params(email: @oauth_user.email)
|
|
117
|
+
|
|
118
|
+
@resource = assigns(:resource)
|
|
119
|
+
@data = JSON.parse(response.body)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
test 'registration is successful' do
|
|
123
|
+
assert_equal 200, response.status
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
test 'a new email-provider user is created' do
|
|
127
|
+
assert @resource.id
|
|
128
|
+
assert_equal 'email', @resource.provider
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# -----------------------------------------------------------------------
|
|
133
|
+
# Mang (another standard model, at /mangs)
|
|
134
|
+
# -----------------------------------------------------------------------
|
|
135
|
+
describe 'alternate standard model (Mang)' do
|
|
136
|
+
before do
|
|
137
|
+
post '/mangs', params: registration_params
|
|
138
|
+
@resource = assigns(:resource)
|
|
139
|
+
@data = JSON.parse(response.body)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
test 'registration is successful' do
|
|
143
|
+
assert_equal 200, response.status
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
test 'resource is a Mang' do
|
|
147
|
+
assert_equal Mang, @resource.class
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
describe 'Mang duplicate email is rejected at model level' do
|
|
152
|
+
before do
|
|
153
|
+
@email = Faker::Internet.unique.email
|
|
154
|
+
create(:mang_user, email: @email, provider: 'email').tap(&:confirm)
|
|
155
|
+
|
|
156
|
+
post '/mangs', params: registration_params(email: @email)
|
|
157
|
+
@data = JSON.parse(response.body)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
test 'request is rejected' do
|
|
161
|
+
assert_equal 422, response.status
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# MultiEmailUser demonstrates a model that uses devise-multi_email alongside
|
|
4
|
+
# DeviseTokenAuth. Email uniqueness is enforced via the emails association/table
|
|
5
|
+
# (managed by Devise::MultiEmail::ParentModelExtensions) rather than by the
|
|
6
|
+
# column-level uniqueness validation that standard models carry.
|
|
7
|
+
#
|
|
8
|
+
# IMPORTANT ordering rules:
|
|
9
|
+
# 1. has_many :emails must be declared BEFORE the multi_email devise modules so
|
|
10
|
+
# Devise::MultiEmail::ParentModelExtensions can reflect on the association.
|
|
11
|
+
# 2. The multi_email devise modules must be called BEFORE including
|
|
12
|
+
# DeviseTokenAuth::Concerns::User so the concern skips its own devise call
|
|
13
|
+
# (it checks method_defined?(:devise_modules) to decide whether to call devise).
|
|
14
|
+
class MultiEmailUser < ActiveRecord::Base
|
|
15
|
+
# 1. Association first — ParentModelExtensions reflects on it at include time.
|
|
16
|
+
# Rails infers the FK as `multi_email_user_id` from the parent class name.
|
|
17
|
+
has_many :emails,
|
|
18
|
+
class_name: 'MultiEmailUserEmail',
|
|
19
|
+
dependent: :destroy
|
|
20
|
+
|
|
21
|
+
# 2–3 only apply when running with ActiveRecord. In Mongoid runs the
|
|
22
|
+
# activerecord gem is still bundled (so ActiveRecord::Base exists) but
|
|
23
|
+
# active_record/railtie is not required, which means devise-multi_email's
|
|
24
|
+
# AR-specific modules are not registered and calling `devise` would raise
|
|
25
|
+
# NoMethodError. We guard here so the file can be safely autoloaded in
|
|
26
|
+
# Mongoid mode (Zeitwerk still gets a valid MultiEmailUser constant).
|
|
27
|
+
if DEVISE_TOKEN_AUTH_ORM == :active_record
|
|
28
|
+
# 2. multi_email devise modules — include Devise::MultiEmail::ParentModelExtensions
|
|
29
|
+
# which adds multi_email_association, find_by_email, and related helpers.
|
|
30
|
+
devise :multi_email_authenticatable, :registerable,
|
|
31
|
+
:recoverable, :multi_email_validatable, :multi_email_confirmable
|
|
32
|
+
|
|
33
|
+
# 3. DeviseTokenAuth concern — sees devise_modules already defined, skips
|
|
34
|
+
# its own devise call, and adds token management, OmniAuth callbacks, etc.
|
|
35
|
+
include DeviseTokenAuth::Concerns::User
|
|
36
|
+
|
|
37
|
+
# 4. Include the delegated `email` method in JSON serialization so that API
|
|
38
|
+
# responses include the primary email even though there is no email column
|
|
39
|
+
# on this table (email lives in the multi_email_user_emails table).
|
|
40
|
+
def as_json(options = {})
|
|
41
|
+
options[:methods] = Array(options[:methods]) | [:email]
|
|
42
|
+
super(options)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Email record for MultiEmailUser. Each row represents one email address
|
|
4
|
+
# that belongs to a MultiEmailUser.
|
|
5
|
+
#
|
|
6
|
+
# The `primary` boolean column is required by the devise-multi_email gem:
|
|
7
|
+
# it generates `primary?` and `primary=` via ActiveRecord from that column name,
|
|
8
|
+
# which ParentModelManager calls to find/set the primary email address.
|
|
9
|
+
#
|
|
10
|
+
# Devise::MultiEmail::EmailModelExtensions (and EmailValidatable) are included
|
|
11
|
+
# automatically into this class by MultiEmailUser's ParentModelExtensions when
|
|
12
|
+
# that model is first loaded — no explicit include is needed here.
|
|
13
|
+
#
|
|
14
|
+
# The association name (:user) must match Devise::MultiEmail.parent_association_name
|
|
15
|
+
# (which defaults to :user). We specify the class and FK explicitly since our
|
|
16
|
+
# parent model is MultiEmailUser (not User) and the FK column is multi_email_user_id.
|
|
17
|
+
class MultiEmailUserEmail < ActiveRecord::Base
|
|
18
|
+
belongs_to :user,
|
|
19
|
+
class_name: 'MultiEmailUser',
|
|
20
|
+
foreign_key: :multi_email_user_id
|
|
21
|
+
end
|
|
@@ -39,7 +39,12 @@ module Dummy
|
|
|
39
39
|
config.autoload_paths << Rails.root.join('lib')
|
|
40
40
|
config.autoload_paths += ["#{config.root}/app/#{DEVISE_TOKEN_AUTH_ORM}"]
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
# legacy_connection_handling was deprecated in Rails 7.0/7.1 and removed in Rails 7.2+
|
|
43
|
+
# Only applies when using ActiveRecord (not when using Mongoid).
|
|
44
|
+
if DEVISE_TOKEN_AUTH_ORM == :active_record &&
|
|
45
|
+
!(Rails::VERSION::MAJOR > 7 || (Rails::VERSION::MAJOR == 7 && Rails::VERSION::MINOR >= 2))
|
|
46
|
+
config.active_record.legacy_connection_handling = false
|
|
47
|
+
end
|
|
43
48
|
|
|
44
49
|
if DEVISE_TOKEN_AUTH_ORM == :mongoid
|
|
45
50
|
Mongoid.configure do |config|
|
|
@@ -2,7 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
Rails.application.config.middleware.use OmniAuth::Builder do |b|
|
|
4
4
|
provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET'], scope: 'email,profile'
|
|
5
|
-
provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET']
|
|
5
|
+
provider :facebook, ENV['FACEBOOK_KEY'], ENV['FACEBOOK_SECRET'],
|
|
6
|
+
setup: lambda { |env|
|
|
7
|
+
req = Rack::Request.new(env)
|
|
8
|
+
|
|
9
|
+
# Persist request params so callback can read them later
|
|
10
|
+
env['rack.session']['dta.omniauth.params'] = req.params.slice(
|
|
11
|
+
'auth_origin_url',
|
|
12
|
+
'omniauth_window_type',
|
|
13
|
+
# include any additional permitted params you support:
|
|
14
|
+
'favorite_color'
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
# If your code expects auth data too:
|
|
18
|
+
# env['rack.session']['dta.omniauth.auth'] = ...
|
|
19
|
+
}
|
|
6
20
|
provider :google_oauth2, ENV['GOOGLE_KEY'], ENV['GOOGLE_SECRET']
|
|
7
21
|
provider :apple, ENV['APPLE_CLIENT_ID'], '', { scope: 'email name', team_id: ENV['APPLE_TEAM_ID'], key_id: ENV['APPLE_KEY'], pem: ENV['APPLE_PEM'] }
|
|
8
22
|
provider :developer,
|
data/test/dummy/config/routes.rb
CHANGED
|
@@ -22,6 +22,14 @@ Rails.application.routes.draw do
|
|
|
22
22
|
|
|
23
23
|
mount_devise_token_auth_for 'ConfirmableUser', at: 'confirmable_user_auth'
|
|
24
24
|
|
|
25
|
+
# MultiEmailUser uses devise-multi_email to manage email addresses via a
|
|
26
|
+
# separate emails association rather than a single email column.
|
|
27
|
+
# Only mount in ActiveRecord mode — the model's devise setup is AR-only.
|
|
28
|
+
if DEVISE_TOKEN_AUTH_ORM == :active_record
|
|
29
|
+
mount_devise_token_auth_for 'MultiEmailUser', at: 'multi_email_auth',
|
|
30
|
+
skip: [:omniauth_callbacks]
|
|
31
|
+
end
|
|
32
|
+
|
|
25
33
|
# test namespacing
|
|
26
34
|
namespace :api do
|
|
27
35
|
scope :v1 do
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
include MigrationDatabaseHelper
|
|
4
|
+
|
|
5
|
+
class DeviseTokenAuthCreateMultiEmailUsers < ActiveRecord::Migration[7.0]
|
|
6
|
+
def change
|
|
7
|
+
create_table(:multi_email_users) do |t|
|
|
8
|
+
## Database authenticatable
|
|
9
|
+
t.string :encrypted_password, null: false, default: ''
|
|
10
|
+
|
|
11
|
+
## Recoverable
|
|
12
|
+
t.string :reset_password_token
|
|
13
|
+
t.datetime :reset_password_sent_at
|
|
14
|
+
t.string :reset_password_redirect_url
|
|
15
|
+
t.boolean :allow_password_change, default: false
|
|
16
|
+
|
|
17
|
+
## Rememberable
|
|
18
|
+
t.datetime :remember_created_at
|
|
19
|
+
|
|
20
|
+
## Confirmable
|
|
21
|
+
t.string :confirmation_token
|
|
22
|
+
t.datetime :confirmed_at
|
|
23
|
+
t.datetime :confirmation_sent_at
|
|
24
|
+
t.string :unconfirmed_email
|
|
25
|
+
|
|
26
|
+
## User Info
|
|
27
|
+
t.string :name
|
|
28
|
+
t.string :nickname
|
|
29
|
+
t.string :image
|
|
30
|
+
|
|
31
|
+
## Unique oauth id
|
|
32
|
+
t.string :provider
|
|
33
|
+
t.string :uid, null: false, default: ''
|
|
34
|
+
|
|
35
|
+
## Tokens
|
|
36
|
+
if json_supported_database?
|
|
37
|
+
t.json :tokens
|
|
38
|
+
else
|
|
39
|
+
t.text :tokens
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
t.timestamps
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
add_index :multi_email_users, [:uid, :provider], unique: true
|
|
46
|
+
add_index :multi_email_users, :reset_password_token, unique: true
|
|
47
|
+
add_index :multi_email_users, :confirmation_token, unique: true
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class DeviseTokenAuthCreateMultiEmailUserEmails < ActiveRecord::Migration[7.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table(:multi_email_user_emails) do |t|
|
|
6
|
+
t.references :multi_email_user, null: false, foreign_key: true, type: :bigint
|
|
7
|
+
t.string :email, null: false
|
|
8
|
+
# devise-multi_email gem requires a column named `primary` (boolean).
|
|
9
|
+
# The gem calls `email_record.primary?` and `email_record.primary = value`
|
|
10
|
+
# which are auto-generated by ActiveRecord from this column name.
|
|
11
|
+
t.boolean :primary, null: false, default: false
|
|
12
|
+
|
|
13
|
+
# Confirmable columns — required by :multi_email_confirmable which
|
|
14
|
+
# includes devise :confirmable into each email record.
|
|
15
|
+
t.string :confirmation_token
|
|
16
|
+
t.datetime :confirmed_at
|
|
17
|
+
t.datetime :confirmation_sent_at
|
|
18
|
+
t.string :unconfirmed_email
|
|
19
|
+
|
|
20
|
+
t.timestamps
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
add_index :multi_email_user_emails, :email, unique: true
|
|
24
|
+
add_index :multi_email_user_emails, :confirmation_token,
|
|
25
|
+
name: 'index_multi_email_user_emails_on_confirmation_token', unique: true
|
|
26
|
+
add_index :multi_email_user_emails, [:multi_email_user_id, :primary],
|
|
27
|
+
name: 'index_multi_email_user_emails_on_user_and_primary'
|
|
28
|
+
end
|
|
29
|
+
end
|