rodauth-rails 1.4.0 → 1.5.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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/README.md +39 -134
  4. data/lib/generators/rodauth/templates/INSTRUCTIONS +11 -1
  5. data/lib/generators/rodauth/templates/app/mailers/rodauth_mailer.rb +38 -52
  6. data/lib/generators/rodauth/templates/app/misc/rodauth_main.rb +9 -6
  7. data/lib/generators/rodauth/templates/app/models/account.rb +1 -0
  8. data/lib/generators/rodauth/templates/app/views/rodauth/add_recovery_codes.html.erb +0 -2
  9. data/lib/generators/rodauth/templates/app/views/rodauth/change_login.html.erb +0 -2
  10. data/lib/generators/rodauth/templates/app/views/rodauth/change_password.html.erb +0 -2
  11. data/lib/generators/rodauth/templates/app/views/rodauth/close_account.html.erb +0 -2
  12. data/lib/generators/rodauth/templates/app/views/rodauth/confirm_password.html.erb +0 -2
  13. data/lib/generators/rodauth/templates/app/views/rodauth/create_account.html.erb +0 -2
  14. data/lib/generators/rodauth/templates/app/views/rodauth/email_auth.html.erb +0 -2
  15. data/lib/generators/rodauth/templates/app/views/rodauth/login.html.erb +0 -2
  16. data/lib/generators/rodauth/templates/app/views/rodauth/logout.html.erb +0 -2
  17. data/lib/generators/rodauth/templates/app/views/rodauth/multi_phase_login.html.erb +0 -2
  18. data/lib/generators/rodauth/templates/app/views/rodauth/otp_auth.html.erb +0 -2
  19. data/lib/generators/rodauth/templates/app/views/rodauth/otp_disable.html.erb +0 -2
  20. data/lib/generators/rodauth/templates/app/views/rodauth/otp_setup.html.erb +0 -2
  21. data/lib/generators/rodauth/templates/app/views/rodauth/recovery_auth.html.erb +0 -2
  22. data/lib/generators/rodauth/templates/app/views/rodauth/recovery_codes.html.erb +0 -2
  23. data/lib/generators/rodauth/templates/app/views/rodauth/remember.html.erb +0 -2
  24. data/lib/generators/rodauth/templates/app/views/rodauth/reset_password.html.erb +0 -2
  25. data/lib/generators/rodauth/templates/app/views/rodauth/reset_password_request.html.erb +0 -2
  26. data/lib/generators/rodauth/templates/app/views/rodauth/sms_auth.html.erb +0 -2
  27. data/lib/generators/rodauth/templates/app/views/rodauth/sms_confirm.html.erb +0 -2
  28. data/lib/generators/rodauth/templates/app/views/rodauth/sms_disable.html.erb +0 -2
  29. data/lib/generators/rodauth/templates/app/views/rodauth/sms_request.html.erb +0 -2
  30. data/lib/generators/rodauth/templates/app/views/rodauth/sms_setup.html.erb +0 -2
  31. data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_auth.html.erb +0 -2
  32. data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_disable.html.erb +0 -2
  33. data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_manage.html.erb +0 -2
  34. data/lib/generators/rodauth/templates/app/views/rodauth/unlock_account.html.erb +0 -2
  35. data/lib/generators/rodauth/templates/app/views/rodauth/unlock_account_request.html.erb +0 -2
  36. data/lib/generators/rodauth/templates/app/views/rodauth/verify_account.html.erb +0 -2
  37. data/lib/generators/rodauth/templates/app/views/rodauth/verify_account_resend.html.erb +0 -2
  38. data/lib/generators/rodauth/templates/app/views/rodauth/verify_login_change.html.erb +0 -2
  39. data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_auth.html.erb +0 -2
  40. data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb +0 -2
  41. data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_setup.html.erb +0 -2
  42. data/lib/generators/rodauth/templates/app/views/rodauth_mailer/verify_login_change.text.erb +2 -2
  43. data/lib/rodauth/rails/feature/render.rb +8 -1
  44. data/lib/rodauth/rails/feature.rb +0 -2
  45. data/lib/rodauth/rails/model.rb +2 -97
  46. data/lib/rodauth/rails/version.rb +1 -1
  47. data/lib/rodauth/rails.rb +3 -2
  48. data/rodauth-rails.gemspec +1 -0
  49. metadata +16 -3
  50. data/lib/rodauth/rails/feature/associations.rb +0 -54
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b5fb22e3d8c84eafedffa3463b4e0ecdf481189b8b48adc2d31005f86251d87
4
- data.tar.gz: 142e229b7c9a9b078f773f99885117268e759df2eb49e5252ce21754dcf61763
3
+ metadata.gz: 43e0f2c048024645cb8af7e744042187ded20eeca3f685bdf28a959aebf296e0
4
+ data.tar.gz: 96d02ad057f315a339bc1cda804f71e19cd629a9cb2ca5c574c515d954692673
5
5
  SHA512:
6
- metadata.gz: b1c30c5b1714a80466ad3775720be50d2f02b8d06d016638e6d1ebfb7515cd6060463b975f9810977fe74eb7330ce12b9c6ff81839e41b2e4044615c606ca7bb
7
- data.tar.gz: 4a532058b27cfc07d2ed234457b880a609c7b35186db976a547be2e83d1c18df7ac72402a9d52155819f2d97edb63b0e7742e908b6cb3ed1b40c2deae18e7e2e
6
+ metadata.gz: c943289cb0c628b37d89fcc6e2a0b22b190ba0e0c0351ffc53c726ac81b0c9f87b0b6e1f929a823724fa1aed70c5b5601279b24df5b54026cb06bb073c3b284c
7
+ data.tar.gz: afb5b6523b6c440c9b02255b047cf562dd0122a6abb8d49f7c93671981c75935d6a1a9ab1c27a9e8158578a928b70b3705db24760db803acd79abafa58cdc4ce
data/CHANGELOG.md CHANGED
@@ -1,3 +1,29 @@
1
+ ## 1.5.0 (2022-06-11)
2
+
3
+ * Remove `content_for` calls from generated view templates (@janko)
4
+
5
+ * Set title instance variable to `@page_title` in generated configuration (@janko)
6
+
7
+ * Set title instance variable on the controller when `title_instance_variable` is set (@HoneyryderChuck)
8
+
9
+ ## 1.4.2 (2022-05-15)
10
+
11
+ * Stop passing email addresses in mailer arguments on verifying login change (@janko)
12
+
13
+ * Extract finding account into a method in the generated mailer (@janko)
14
+
15
+ * Make generated Action Mailer integration work with secondary Rodauth configurations (@janko)
16
+
17
+ * Include `Rodauth::Rails.model` in generated Sequel account model as well (@janko)
18
+
19
+ ## 1.4.1 (2022-05-08)
20
+
21
+ * Deprecate `Rodauth::Rails::Model` constant (@janko)
22
+
23
+ * Remove `Rodauth::Rails::Auth#associations` in favour of new association registration API (@janko)
24
+
25
+ * Extract model mixin into the rodauth-model gem (@janko)
26
+
1
27
  ## 1.4.0 (2022-05-04)
2
28
 
3
29
  * Move association definitions to `#associations` Rodauth method, allowing external features to extend them (@janko)
data/README.md CHANGED
@@ -321,16 +321,26 @@ $ rails generate rodauth:views webauthn --name admin
321
321
 
322
322
  #### Page titles
323
323
 
324
- The generated view templates use `content_for(:title)` to store Rodauth's page
325
- titles, which you can then retrieve in your layout template to set the page
326
- title:
324
+ The generated configuration sets `title_instance_variable` to make page titles
325
+ available in your views via `@page_title` instance variable, which you can then
326
+ use in your layout:
327
327
 
328
+ ```rb
329
+ # app/misc/rodauth_main.rb
330
+ class RodauthMain < Rodauth::Rails::Auth
331
+ configure do
332
+ # ...
333
+ title_instance_variable :@page_title
334
+ # ...
335
+ end
336
+ end
337
+ ```
328
338
  ```erb
329
339
  <!-- app/views/layouts/application.html.erb -->
330
340
  <!DOCTYPE html>
331
341
  <html>
332
342
  <head>
333
- <title><%= content_for(:title) %></title>
343
+ <title><%= @page_title || "Default title" %></title>
334
344
  <!-- ... -->
335
345
  </head>
336
346
  <body>
@@ -339,6 +349,21 @@ title:
339
349
  </html>
340
350
  ```
341
351
 
352
+ If you're already setting page titles via `content_for`, you can use it in
353
+ generated Rodauth views, giving it the result of the corresponding
354
+ `*_page_title` method:
355
+
356
+ ```erb
357
+ <!-- app/views/rodauth/login.html.erb -->
358
+ <%= content_for :page_title, rodauth.login_page_title %>
359
+ <!-- ... -->
360
+ ```
361
+ ```erb
362
+ <!-- app/views/rodauth/change_password.html.erb -->
363
+ <%= content_for :page_title, rodauth.change_password_page_title %>
364
+ <!-- ... -->
365
+ ```
366
+
342
367
  #### Layout
343
368
 
344
369
  To use different layouts for different Rodauth views, you can compare the
@@ -484,21 +509,19 @@ end
484
509
 
485
510
  ## Model
486
511
 
487
- The `Rodauth::Rails::Model` mixin can be included into the account model, which
488
- defines a password attribute and associations for tables used by enabled
489
- authentication features.
512
+ The [rodauth-model] gem provides a `Rodauth::Model` mixin that can be included
513
+ into the account model, which defines a password attribute and associations for
514
+ tables used by enabled authentication features.
490
515
 
491
516
  ```rb
492
- class Account < ApplicationRecord
517
+ class Account < ActiveRecord::Base # Sequel::Model
493
518
  include Rodauth::Rails.model # or `Rodauth::Rails.model(:admin)`
494
519
  end
495
520
  ```
496
521
 
497
- ### Password attribute
498
-
499
- Regardless of whether you're storing the password hash in a column in the
500
- accounts table, or in a separate table, the `#password` attribute can be used
501
- to set or clear the password hash.
522
+ The password attribute can be used to set or clear the password hash. It
523
+ handles both storing the password hash in a column on the accounts table, or in
524
+ a separate table.
502
525
 
503
526
  ```rb
504
527
  account = Account.create!(email: "user@example.com", password: "secret")
@@ -514,132 +537,14 @@ account.password = nil # clears password hash
514
537
  account.password_hash #=> nil
515
538
  ```
516
539
 
517
- Note that the password attribute doesn't come with validations, making it
518
- unsuitable for forms. It was primarily intended to allow easily creating
519
- accounts in development console and in tests.
520
-
521
- ### Associations
522
-
523
- The `Rodauth::Rails::Model` mixin defines associations for Rodauth tables
524
- associated to the accounts table:
540
+ The associations are defined for tables used by enabled authentication features:
525
541
 
526
542
  ```rb
527
543
  account.remember_key #=> #<Account::RememberKey> (record from `account_remember_keys` table)
528
544
  account.active_session_keys #=> [#<Account::ActiveSessionKey>,...] (records from `account_active_session_keys` table)
529
545
  ```
530
546
 
531
- You can also reference the associated models directly:
532
-
533
- ```rb
534
- # model referencing the `account_authentication_audit_logs` table
535
- Account::AuthenticationAuditLog.where(message: "login").group(:account_id)
536
- ```
537
-
538
- The associated models define the inverse `belongs_to :account` association:
539
-
540
- ```rb
541
- Account::ActiveSessionKey.includes(:account).map(&:account)
542
- ```
543
-
544
- Here is an example of using associations to create a method that returns
545
- whether the account has multifactor authentication enabled:
546
-
547
- ```rb
548
- class Account < ApplicationRecord
549
- include Rodauth::Rails.model
550
-
551
- def mfa_enabled?
552
- otp_key || (sms_code && sms_code.num_failures.nil?) || recovery_codes.any?
553
- end
554
- end
555
- ```
556
-
557
- Here is another example of creating a query scope that selects accounts with
558
- multifactor authentication enabled:
559
-
560
- ```rb
561
- class Account < ApplicationRecord
562
- include Rodauth::Rails.model
563
-
564
- scope :otp_setup, -> { where(otp_key: OtpKey.all) }
565
- scope :sms_codes_setup, -> { where(sms_code: SmsCode.where(num_failures: nil)) }
566
- scope :recovery_codes_setup, -> { where(recovery_codes: RecoveryCode.all) }
567
- scope :mfa_enabled, -> { merge(otp_setup.or(sms_codes_setup).or(recovery_codes_setup)) }
568
- end
569
- ```
570
-
571
- #### Association reference
572
-
573
- Below is a list of all associations defined depending on the features loaded:
574
-
575
- | Feature | Association | Type | Model | Table (default) |
576
- | :------ | :---------- | :--- | :---- | :---- |
577
- | account_expiration | `:activity_time` | `has_one` | `ActivityTime` | `account_activity_times` |
578
- | active_sessions | `:active_session_keys` | `has_many` | `ActiveSessionKey` | `account_active_session_keys` |
579
- | audit_logging | `:authentication_audit_logs` | `has_many` | `AuthenticationAuditLog` | `account_authentication_audit_logs` |
580
- | disallow_password_reuse | `:previous_password_hashes` | `has_many` | `PreviousPasswordHash` | `account_previous_password_hashes` |
581
- | email_auth | `:email_auth_key` | `has_one` | `EmailAuthKey` | `account_email_auth_keys` |
582
- | jwt_refresh | `:jwt_refresh_keys` | `has_many` | `JwtRefreshKey` | `account_jwt_refresh_keys` |
583
- | lockout | `:lockout` | `has_one` | `Lockout` | `account_lockouts` |
584
- | lockout | `:login_failure` | `has_one` | `LoginFailure` | `account_login_failures` |
585
- | otp | `:otp_key` | `has_one` | `OtpKey` | `account_otp_keys` |
586
- | password_expiration | `:password_change_time` | `has_one` | `PasswordChangeTime` | `account_password_change_times` |
587
- | recovery_codes | `:recovery_codes` | `has_many` | `RecoveryCode` | `account_recovery_codes` |
588
- | remember | `:remember_key` | `has_one` | `RememberKey` | `account_remember_keys` |
589
- | reset_password | `:password_reset_key` | `has_one` | `PasswordResetKey` | `account_password_reset_keys` |
590
- | single_session | `:session_key` | `has_one` | `SessionKey` | `account_session_keys` |
591
- | sms_codes | `:sms_code` | `has_one` | `SmsCode` | `account_sms_codes` |
592
- | verify_account | `:verification_key` | `has_one` | `VerificationKey` | `account_verification_keys` |
593
- | verify_login_change | `:login_change_key` | `has_one` | `LoginChangeKey` | `account_login_change_keys` |
594
- | webauthn | `:webauthn_keys` | `has_many` | `WebauthnKey` | `account_webauthn_keys` |
595
- | webauthn | `:webauthn_user_id` | `has_one` | `WebauthnUserId` | `account_webauthn_user_ids` |
596
-
597
- Note that some Rodauth tables use composite primary keys, which Active Record
598
- doesn't support out of the box. For associations to work properly, you might
599
- need to add the [composite_primary_keys] gem to your Gemfile.
600
-
601
- #### Association options
602
-
603
- By default, all associations except for audit logs have `dependent: :destroy`
604
- set, to allow for easy deletion of account records in the console. You can use
605
- `:association_options` to modify global or per-association options:
606
-
607
- ```rb
608
- # don't auto-delete associations when account model is deleted
609
- Rodauth::Rails.model(association_options: { dependent: nil })
610
-
611
- # require authentication audit logs to be eager loaded before retrieval
612
- Rodauth::Rails.model(association_options: -> (name) {
613
- { strict_loading: true } if name == :authentication_audit_logs
614
- })
615
- ```
616
-
617
- #### Extending Associations
618
-
619
- External features can extend the list of associations with their own
620
- definitions, which the model mixin will pick up and declare the new associations
621
- on the model.
622
-
623
- ```rb
624
- # lib/rodauth/features/foo.rb
625
- module Rodauth
626
- Feature.define(:foo, :Foo) do
627
- auth_value_method :foo_table, :account_foos
628
- auth_value_method :foo_id_column, :id
629
-
630
- def associations
631
- list = super
632
- list << {
633
- name: :foo, # will define `Account::Foo` model
634
- type: :one, # or :many
635
- table: foo_table,
636
- foreign_key: foo_id_column
637
- }
638
- list
639
- end
640
- end
641
- end
642
- ```
547
+ See the [rodauth-model] documentation for more details.
643
548
 
644
549
  ## Multiple configurations
645
550
 
@@ -1304,8 +1209,8 @@ conduct](https://github.com/janko/rodauth-rails/blob/master/CODE_OF_CONDUCT.md).
1304
1209
  [account_expiration]: http://rodauth.jeremyevans.net/rdoc/files/doc/account_expiration_rdoc.html
1305
1210
  [simple_ldap_authenticator]: https://github.com/jeremyevans/simple_ldap_authenticator
1306
1211
  [internal_request]: http://rodauth.jeremyevans.net/rdoc/files/doc/internal_request_rdoc.html
1307
- [composite_primary_keys]: https://github.com/composite-primary-keys/composite_primary_keys
1308
1212
  [path_class_methods]: https://rodauth.jeremyevans.net/rdoc/files/doc/path_class_methods_rdoc.html
1309
1213
  [account types]: https://github.com/janko/rodauth-rails/wiki/Account-Types
1310
1214
  [custom mailer worker]: https://github.com/janko/rodauth-rails/wiki/Custom-Mailer-Worker
1311
1215
  [Turbo]: https://turbo.hotwired.dev/
1216
+ [rodauth-model]: https://github.com/janko/rodauth-model
@@ -31,7 +31,17 @@ Depending on your application's configuration some manual setup may be required:
31
31
 
32
32
  * Not required for API-only Applications *
33
33
 
34
- 4. You can copy Rodauth views (for customization) to your app by running:
34
+ 4. Titles for Rodauth pages are available via @page_title instance variable
35
+ by default, you can use it in your layout file:
36
+
37
+ <head>
38
+ <title><%= @page_title || "Default title" %></title>
39
+ ...
40
+ </head>
41
+
42
+ * Not required *
43
+
44
+ 5. You can copy Rodauth views (for customization) to your app by running:
35
45
 
36
46
  rails g rodauth:views
37
47
 
@@ -1,78 +1,64 @@
1
1
  class RodauthMailer < ApplicationMailer
2
- def verify_account(account_id, key)
3
- @email_link = rodauth.verify_account_url(key: email_token(account_id, key))
4
- <% if defined?(ActiveRecord::Railtie) -%>
5
- @account = Account.find(account_id)
6
- <% else -%>
7
- @account = Account.with_pk!(account_id)
8
- <% end -%>
2
+ def verify_account(name = nil, account_id, key)
3
+ @email_link = email_link(name, :verify_account, account_id, key)
4
+ @account = find_account(name, account_id)
9
5
 
10
- mail to: @account.email, subject: rodauth.verify_account_email_subject
6
+ mail to: @account.email, subject: rodauth(name).verify_account_email_subject
11
7
  end
12
8
 
13
- def reset_password(account_id, key)
14
- @email_link = rodauth.reset_password_url(key: email_token(account_id, key))
15
- <% if defined?(ActiveRecord::Railtie) -%>
16
- @account = Account.find(account_id)
17
- <% else -%>
18
- @account = Account.with_pk!(account_id)
19
- <% end -%>
9
+ def reset_password(name = nil, account_id, key)
10
+ @email_link = email_link(name, :reset_password, account_id, key)
11
+ @account = find_account(name, account_id)
20
12
 
21
- mail to: @account.email, subject: rodauth.reset_password_email_subject
13
+ mail to: @account.email, subject: rodauth(name).reset_password_email_subject
22
14
  end
23
15
 
24
- def verify_login_change(account_id, old_login, new_login, key)
25
- @old_login = old_login
26
- @new_login = new_login
27
- @email_link = rodauth.verify_login_change_url(key: email_token(account_id, key))
28
- <% if defined?(ActiveRecord::Railtie) -%>
29
- @account = Account.find(account_id)
30
- <% else -%>
31
- @account = Account.with_pk!(account_id)
32
- <% end -%>
16
+ def verify_login_change(name = nil, account_id, key)
17
+ @email_link = email_link(name, :verify_login_change, account_id, key)
18
+ @account = find_account(name, account_id)
19
+ @new_email = @account.login_change_key.login
33
20
 
34
- mail to: new_login, subject: rodauth.verify_login_change_email_subject
21
+ mail to: @new_email, subject: rodauth(name).verify_login_change_email_subject
35
22
  end
36
23
 
37
- def password_changed(account_id)
38
- <% if defined?(ActiveRecord::Railtie) -%>
39
- @account = Account.find(account_id)
40
- <% else -%>
41
- @account = Account.with_pk!(account_id)
42
- <% end -%>
24
+ def password_changed(name = nil, account_id)
25
+ @account = find_account(name, account_id)
43
26
 
44
- mail to: @account.email, subject: rodauth.password_changed_email_subject
27
+ mail to: @account.email, subject: rodauth(name).password_changed_email_subject
45
28
  end
46
29
 
47
- # def email_auth(account_id, key)
48
- # @email_link = rodauth.email_auth_url(key: email_token(account_id, key))
49
- <% if defined?(ActiveRecord::Railtie) -%>
50
- # @account = Account.find(account_id)
51
- <% else -%>
52
- # @account = Account.with_pk!(account_id)
53
- <% end -%>
30
+ # def email_auth(name = nil, account_id, key)
31
+ # @email_link = email_link(name, :email_auth, account_id, key)
32
+ # @account = find_account(name, account_id)
54
33
 
55
- # mail to: @account.email, subject: rodauth.email_auth_email_subject
34
+ # mail to: @account.email, subject: rodauth(name).email_auth_email_subject
56
35
  # end
57
36
 
58
- # def unlock_account(account_id, key)
59
- # @email_link = rodauth.unlock_account_url(key: email_token(account_id, key))
60
- <% if defined?(ActiveRecord::Railtie) -%>
61
- # @account = Account.find(account_id)
62
- <% else -%>
63
- # @account = Account.with_pk!(account_id)
64
- <% end -%>
37
+ # def unlock_account(name = nil, account_id, key)
38
+ # @email_link = email_link(name, :unlock_account, account_id, key)
39
+ # @account = find_account(name, account_id)
65
40
 
66
- # mail to: @account.email, subject: rodauth.unlock_account_email_subject
41
+ # mail to: @account.email, subject: rodauth(name).unlock_account_email_subject
67
42
  # end
68
43
 
69
44
  private
70
45
 
71
- def email_token(account_id, key)
72
- "#{account_id}_#{rodauth.compute_hmac(key)}"
46
+ def find_account(_name, account_id)
47
+ <% if defined?(ActiveRecord::Railtie) -%>
48
+ Account.find(account_id)
49
+ <% else -%>
50
+ Account.with_pk!(account_id)
51
+ <% end -%>
52
+ end
53
+
54
+ def email_link(name, action, account_id, key)
55
+ instance = rodauth(name)
56
+ instance.instance_variable_set(:@account, { id: account_id })
57
+ instance.instance_variable_set(:"@#{action}_key_value", key)
58
+ instance.public_send(:"#{action}_email_link")
73
59
  end
74
60
 
75
- def rodauth(name = nil)
61
+ def rodauth(name)
76
62
  RodauthApp.rodauth(name).allocate
77
63
  end
78
64
  end
@@ -31,6 +31,9 @@ class RodauthMain < Rodauth::Rails::Auth
31
31
  # Specify the controller used for view rendering and CSRF verification.
32
32
  rails_controller { RodauthController }
33
33
 
34
+ # Set on Rodauth controller with the title of the current page.
35
+ title_instance_variable :@page_title
36
+
34
37
  # Store account status in an integer column without foreign key constraint.
35
38
  account_status_column :status
36
39
 
@@ -56,22 +59,22 @@ class RodauthMain < Rodauth::Rails::Auth
56
59
  # ==> Emails
57
60
  # Use a custom mailer for delivering authentication emails.
58
61
  create_reset_password_email do
59
- RodauthMailer.reset_password(account_id, reset_password_key_value)
62
+ RodauthMailer.reset_password(*self.class.configuration_name, account_id, reset_password_key_value)
60
63
  end
61
64
  create_verify_account_email do
62
- RodauthMailer.verify_account(account_id, verify_account_key_value)
65
+ RodauthMailer.verify_account(*self.class.configuration_name, account_id, verify_account_key_value)
63
66
  end
64
67
  create_verify_login_change_email do |_login|
65
- RodauthMailer.verify_login_change(account_id, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_key_value)
68
+ RodauthMailer.verify_login_change(*self.class.configuration_name, account_id, verify_login_change_key_value)
66
69
  end
67
70
  create_password_changed_email do
68
- RodauthMailer.password_changed(account_id)
71
+ RodauthMailer.password_changed(*self.class.configuration_name, account_id)
69
72
  end
70
73
  # create_email_auth_email do
71
- # RodauthMailer.email_auth(account_id, email_auth_key_value)
74
+ # RodauthMailer.email_auth(*self.class.configuration_name, account_id, email_auth_key_value)
72
75
  # end
73
76
  # create_unlock_account_email do
74
- # RodauthMailer.unlock_account(account_id, unlock_account_key_value)
77
+ # RodauthMailer.unlock_account(*self.class.configuration_name, account_id, unlock_account_key_value)
75
78
  # end
76
79
  send_email do |email|
77
80
  # queue email delivery on the mailer after the transaction commits
@@ -9,6 +9,7 @@ class Account < ApplicationRecord
9
9
  end
10
10
  <% else -%>
11
11
  class Account < Sequel::Model
12
+ include Rodauth::Rails.model
12
13
  plugin :enum
13
14
  enum :status, unverified: 1, verified: 2, closed: 3
14
15
  end
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.add_recovery_codes_page_title %>
2
-
3
1
  <pre id="recovery-codes"><%= rodauth.recovery_codes.map { |s| h(s) }.join("\n\n") %></pre>
4
2
 
5
3
  <% if rodauth.can_add_recovery_codes? %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.change_login_page_title %>
2
-
3
1
  <%= form_with url: rodauth.change_login_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <div class="form-group mb-3">
5
3
  <%= form.label "login", rodauth.login_label, class: "form-label" %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.change_password_page_title %>
2
-
3
1
  <%= form_with url: rodauth.change_password_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <% if rodauth.change_password_requires_password? %>
5
3
  <div class="form-group mb-3">
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.close_account_page_title %>
2
-
3
1
  <%= form_with url: rodauth.close_account_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <% if rodauth.close_account_requires_password? %>
5
3
  <div class="form-group mb-3">
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.confirm_password_page_title %>
2
-
3
1
  <%= form_with url: rodauth.confirm_password_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <div class="form-group mb-3">
5
3
  <%= form.label "password", rodauth.password_label, class: "form-label" %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.create_account_page_title %>
2
-
3
1
  <%= form_with url: rodauth.create_account_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <div class="form-group mb-3">
5
3
  <%= form.label "login", rodauth.login_label, class: "form-label" %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.email_auth_page_title %>
2
-
3
1
  <%= form_with url: rodauth.email_auth_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <div class="form-group mb-3">
5
3
  <%= form.submit rodauth.login_button, class: "btn btn-primary" %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.login_page_title %>
2
-
3
1
  <%= render "login_form_header" %>
4
2
  <%= render "login_form" %>
5
3
  <%= render "login_form_footer" %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.logout_page_title %>
2
-
3
1
  <%= form_with url: rodauth.logout_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <% if rodauth.features.include?(:active_sessions) %>
5
3
  <div class="form-group mb-3">
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.multi_phase_login_page_title %>
2
-
3
1
  <%= render "login_form_header" %>
4
2
  <%== rodauth.render_multi_phase_login_forms %>
5
3
  <%= render "login_form_footer" %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.otp_auth_page_title %>
2
-
3
1
  <%= form_with url: rodauth.otp_auth_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <div class="form-group mb-3">
5
3
  <%= form.label "otp-auth-code", rodauth.otp_auth_label, class: "form-label" %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.otp_disable_page_title %>
2
-
3
1
  <%= form_with url: rodauth.otp_disable_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <% if rodauth.two_factor_modifications_require_password? %>
5
3
  <div class="form-group mb-3">
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.otp_setup_page_title %>
2
-
3
1
  <%= form_with url: rodauth.otp_setup_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <%= form.hidden_field rodauth.otp_setup_param, value: rodauth.otp_user_key, id: "otp-key" %>
5
3
  <%= form.hidden_field rodauth.otp_setup_raw_param, value: rodauth.otp_key, id: "otp-hmac-secret" if rodauth.otp_keys_use_hmac? %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.recovery_auth_page_title %>
2
-
3
1
  <%= form_with url: rodauth.recovery_auth_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <div class="form-group mb-3">
5
3
  <%= form.label "recovery-code", rodauth.recovery_codes_label, class: "form-label" %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.recovery_codes_page_title %>
2
-
3
1
  <%= form_with url: rodauth.recovery_codes_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <% if rodauth.two_factor_modifications_require_password? %>
5
3
  <div class="form-group mb-3">
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.remember_page_title %>
2
-
3
1
  <%= form_with url: rodauth.remember_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <fieldset class="form-group mb-3">
5
3
  <div class="form-check">
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.reset_password_page_title %>
2
-
3
1
  <%= form_with url: rodauth.reset_password_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <div class="form-group mb-3">
5
3
  <%= form.label "password", rodauth.password_label, class: "form-label" %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.reset_password_request_page_title %>
2
-
3
1
  <%= form_with url: rodauth.reset_password_request_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <%== rodauth.reset_password_explanatory_text %>
5
3
 
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.sms_auth_page_title %>
2
-
3
1
  <%= form_with url: rodauth.sms_auth_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <div class="form-group mb-3">
5
3
  <%= form.label "sms-code", rodauth.sms_code_label, class: "form-label" %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.sms_confirm_page_title %>
2
-
3
1
  <%= form_with url: rodauth.sms_confirm_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <div class="form-group mb-3">
5
3
  <%= form.label "sms-code", rodauth.sms_code_label, class: "form-label" %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.sms_disable_page_title %>
2
-
3
1
  <%= form_with url: rodauth.sms_disable_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <% if rodauth.two_factor_modifications_require_password? %>
5
3
  <div class="form-group mb-3">
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.sms_request_page_title %>
2
-
3
1
  <%= form_with url: rodauth.sms_request_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <div class="form-group mb-3">
5
3
  <%= form.submit rodauth.sms_request_button, class: "btn btn-primary" %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.sms_setup_page_title %>
2
-
3
1
  <%= form_with url: rodauth.sms_setup_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <% if rodauth.two_factor_modifications_require_password? %>
5
3
  <div class="form-group mb-3">
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.two_factor_auth_page_title %>
2
-
3
1
  <ul>
4
2
  <% rodauth.two_factor_auth_links.sort.each do |_, link, text| %>
5
3
  <li><%= link_to text, link %></li>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.two_factor_disable_page_title %>
2
-
3
1
  <%= form_with url: rodauth.two_factor_disable_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <% if rodauth.two_factor_modifications_require_password? %>
5
3
  <div class="form-group mb-3">
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.two_factor_manage_page_title %>
2
-
3
1
  <% if rodauth.two_factor_setup_links.any? %>
4
2
  <%== rodauth.two_factor_setup_heading %>
5
3
 
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.unlock_account_page_title %>
2
-
3
1
  <%= form_with url: rodauth.unlock_account_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <%== rodauth.unlock_account_explanatory_text %>
5
3
 
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.unlock_account_request_page_title %>
2
-
3
1
  <%= form_with url: rodauth.unlock_account_request_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <%= form.hidden_field rodauth.login_param, value: params[rodauth.login_param] %>
5
3
 
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.verify_account_page_title %>
2
-
3
1
  <%= form_with url: rodauth.verify_account_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <% if rodauth.verify_account_set_password? %>
5
3
  <div class="form-group mb-3">
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.resend_verify_account_page_title %>
2
-
3
1
  <%= form_with url: rodauth.verify_account_resend_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <%== rodauth.verify_account_resend_explanatory_text %>
5
3
 
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.verify_login_change_page_title %>
2
-
3
1
  <%= form_with url: rodauth.verify_login_change_path, method: :post, data: { turbo: false } do |form| %>
4
2
  <div class="form-group mb-3">
5
3
  <%= form.submit rodauth.verify_login_change_button, class: "btn btn-primary" %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.webauthn_auth_page_title %>
2
-
3
1
  <% cred = rodauth.webauth_credential_options_for_get %>
4
2
 
5
3
  <%= form_with url: rodauth.webauthn_auth_form_path, method: :post, id: "webauthn-auth-form", data: { credential_options: cred.as_json.to_json, turbo: false } do |form| %>
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.webauthn_remove_page_title %>
2
-
3
1
  <%= form_with url: rodauth.webauthn_remove_path, method: :post, id: "webauthn-remove-form", data: { turbo: false } do |form| %>
4
2
  <% if rodauth.two_factor_modifications_require_password? %>
5
3
  <div class="form-group mb-3">
@@ -1,5 +1,3 @@
1
- <% content_for :title, rodauth.webauthn_setup_page_title %>
2
-
3
1
  <% cred = rodauth.new_webauthn_credential %>
4
2
 
5
3
  <%= form_with url: rodauth.webauthn_setup_path, method: :post, id: "webauthn-setup-form", data: { credential_options: cred.as_json.to_json, turbo: false } do |form| %>
@@ -1,8 +1,8 @@
1
1
  Someone with an account has requested their login be changed to this email address:
2
2
 
3
- Old email: <%= @old_login %>
3
+ Old email: <%= @account.email %>
4
4
 
5
- New email: <%= @new_login %>
5
+ New email: <%= @new_email %>
6
6
 
7
7
  If you did not request this login change, please ignore this message. If you
8
8
  requested this login change, please go to
@@ -8,7 +8,8 @@ module Rodauth
8
8
 
9
9
  # Renders templates with layout. First tries to render a user-defined
10
10
  # template, otherwise falls back to Rodauth's template.
11
- def view(page, *)
11
+ def view(page, title)
12
+ set_title(title)
12
13
  rails_render(action: page.tr("-", "_"), layout: true) ||
13
14
  rails_render(html: super.html_safe, layout: true, formats: :html)
14
15
  end
@@ -50,6 +51,12 @@ module Rodauth
50
51
  html = html.gsub(/<form(.+)>/, '<form\1 data-turbo="false">') if meth == :view
51
52
  html
52
53
  end
54
+
55
+ def set_title(title)
56
+ if title_instance_variable
57
+ rails_controller_instance.instance_variable_set(title_instance_variable, title)
58
+ end
59
+ end
53
60
  end
54
61
  end
55
62
  end
@@ -11,7 +11,6 @@ module Rodauth
11
11
  require "rodauth/rails/feature/email"
12
12
  require "rodauth/rails/feature/instrumentation"
13
13
  require "rodauth/rails/feature/internal_request"
14
- require "rodauth/rails/feature/associations"
15
14
 
16
15
  include Rodauth::Rails::Feature::Base
17
16
  include Rodauth::Rails::Feature::Callbacks
@@ -20,6 +19,5 @@ module Rodauth
20
19
  include Rodauth::Rails::Feature::Email
21
20
  include Rodauth::Rails::Feature::Instrumentation
22
21
  include Rodauth::Rails::Feature::InternalRequest
23
- include Rodauth::Rails::Feature::Associations
24
22
  end
25
23
  end
@@ -1,101 +1,6 @@
1
1
  module Rodauth
2
2
  module Rails
3
- class Model < Module
4
- ASSOCIATION_TYPES = { one: :has_one, many: :has_many }
5
-
6
- def initialize(auth_class, association_options: {})
7
- @auth_class = auth_class
8
- @association_options = association_options
9
-
10
- define_methods
11
- end
12
-
13
- def included(model)
14
- fail Rodauth::Rails::Error, "must be an Active Record model" unless model < ActiveRecord::Base
15
-
16
- define_associations(model)
17
- end
18
-
19
- private
20
-
21
- def define_methods
22
- rodauth = @auth_class.allocate.freeze
23
-
24
- attr_reader :password
25
-
26
- define_method(:password=) do |password|
27
- @password = password
28
- password_hash = rodauth.send(:password_hash, password) if password
29
- set_password_hash(password_hash)
30
- end
31
-
32
- define_method(:set_password_hash) do |password_hash|
33
- if rodauth.account_password_hash_column
34
- public_send(:"#{rodauth.account_password_hash_column}=", password_hash)
35
- else
36
- if password_hash
37
- record = self.password_hash || build_password_hash
38
- record.public_send(:"#{rodauth.password_hash_column}=", password_hash)
39
- else
40
- self.password_hash&.mark_for_destruction
41
- end
42
- end
43
- end
44
- end
45
-
46
- def define_associations(model)
47
- define_password_hash_association(model) unless rodauth.account_password_hash_column
48
-
49
- rodauth.associations.each do |association|
50
- define_association(model, **association, type: ASSOCIATION_TYPES.fetch(association[:type]))
51
- end
52
- end
53
-
54
- def define_password_hash_association(model)
55
- password_hash_id_column = rodauth.password_hash_id_column
56
- scope = -> { select(password_hash_id_column) } if rodauth.send(:use_database_authentication_functions?)
57
-
58
- define_association model,
59
- type: :has_one,
60
- name: :password_hash,
61
- table: rodauth.password_hash_table,
62
- foreign_key: password_hash_id_column,
63
- scope: scope,
64
- autosave: true
65
- end
66
-
67
- def define_association(model, type:, name:, table:, foreign_key:, scope: nil, **options)
68
- associated_model = Class.new(model.superclass)
69
- associated_model.table_name = table
70
- associated_model.belongs_to :account,
71
- class_name: model.name,
72
- foreign_key: foreign_key,
73
- inverse_of: name
74
-
75
- model.const_set(name.to_s.singularize.camelize, associated_model)
76
-
77
- unless name == :authentication_audit_logs
78
- dependent = type == :has_many ? :delete_all : :delete
79
- end
80
-
81
- model.public_send type, name, scope,
82
- class_name: associated_model.name,
83
- foreign_key: foreign_key,
84
- dependent: dependent,
85
- inverse_of: :account,
86
- **options,
87
- **association_options(name)
88
- end
89
-
90
- def association_options(name)
91
- options = @association_options
92
- options = options.call(name) if options.respond_to?(:call)
93
- options || {}
94
- end
95
-
96
- def rodauth
97
- @auth_class.allocate
98
- end
99
- end
3
+ Model = Rodauth::Model
4
+ deprecate_constant :Model
100
5
  end
101
6
  end
@@ -1,5 +1,5 @@
1
1
  module Rodauth
2
2
  module Rails
3
- VERSION = "1.4.0"
3
+ VERSION = "1.5.0"
4
4
  end
5
5
  end
data/lib/rodauth/rails.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "rodauth/rails/version"
2
2
  require "rodauth/rails/railtie"
3
+ require "rodauth/model"
3
4
 
4
5
  module Rodauth
5
6
  module Rails
@@ -15,7 +16,7 @@ module Rodauth
15
16
  @middleware = true
16
17
 
17
18
  class << self
18
- def rodauth(name = nil, query: nil, form: nil, account: nil, **options)
19
+ def rodauth(name = nil, account: nil, **options)
19
20
  auth_class = app.rodauth!(name)
20
21
 
21
22
  unless auth_class.features.include?(:internal_request)
@@ -43,7 +44,7 @@ module Rodauth
43
44
  end
44
45
 
45
46
  def model(name = nil, **options)
46
- Rodauth::Rails::Model.new(app.rodauth!(name), **options)
47
+ Rodauth::Model.new(app.rodauth!(name), **options)
47
48
  end
48
49
 
49
50
  # routing constraint that requires authentication
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.add_dependency "rodauth", "~> 2.23"
21
21
  spec.add_dependency "roda", "~> 3.55"
22
22
  spec.add_dependency "sequel-activerecord_connection", "~> 1.1"
23
+ spec.add_dependency "rodauth-model", "~> 0.2"
23
24
  spec.add_dependency "tilt"
24
25
  spec.add_dependency "bcrypt"
25
26
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rodauth-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janko Marohnić
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-05-04 00:00:00.000000000 Z
11
+ date: 2022-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -72,6 +72,20 @@ dependencies:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: '1.1'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rodauth-model
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.2'
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.2'
75
89
  - !ruby/object:Gem::Dependency
76
90
  name: tilt
77
91
  requirement: !ruby/object:Gem::Requirement
@@ -264,7 +278,6 @@ files:
264
278
  - lib/rodauth/rails/auth.rb
265
279
  - lib/rodauth/rails/controller_methods.rb
266
280
  - lib/rodauth/rails/feature.rb
267
- - lib/rodauth/rails/feature/associations.rb
268
281
  - lib/rodauth/rails/feature/base.rb
269
282
  - lib/rodauth/rails/feature/callbacks.rb
270
283
  - lib/rodauth/rails/feature/csrf.rb
@@ -1,54 +0,0 @@
1
- module Rodauth
2
- module Rails
3
- module Feature
4
- module Associations
5
- def associations
6
- list = []
7
-
8
- features.each do |feature|
9
- case feature
10
- when :remember
11
- list << { name: :remember_key, type: :one, table: remember_table, foreign_key: remember_id_column }
12
- when :verify_account
13
- list << { name: :verification_key, type: :one, table: verify_account_table, foreign_key: verify_account_id_column }
14
- when :reset_password
15
- list << { name: :password_reset_key, type: :one, table: reset_password_table, foreign_key: reset_password_id_column }
16
- when :verify_login_change
17
- list << { name: :login_change_key, type: :one, table: verify_login_change_table, foreign_key: verify_login_change_id_column }
18
- when :lockout
19
- list << { name: :lockout, type: :one, table: account_lockouts_table, foreign_key: account_lockouts_id_column }
20
- list << { name: :login_failure, type: :one, table: account_login_failures_table, foreign_key: account_login_failures_id_column }
21
- when :email_auth
22
- list << { name: :email_auth_key, type: :one, table: email_auth_table, foreign_key: email_auth_id_column }
23
- when :account_expiration
24
- list << { name: :activity_time, type: :one, table: account_activity_table, foreign_key: account_activity_id_column }
25
- when :active_sessions
26
- list << { name: :active_session_keys, type: :many, table: active_sessions_table, foreign_key: active_sessions_account_id_column }
27
- when :audit_logging
28
- list << { name: :authentication_audit_logs, type: :many, table: audit_logging_table, foreign_key: audit_logging_account_id_column }
29
- when :disallow_password_reuse
30
- list << { name: :previous_password_hashes, type: :many, table: previous_password_hash_table, foreign_key: previous_password_account_id_column }
31
- when :jwt_refresh
32
- list << { name: :jwt_refresh_keys, type: :many, table: jwt_refresh_token_table, foreign_key: jwt_refresh_token_account_id_column }
33
- when :password_expiration
34
- list << { name: :password_change_time, type: :one, table: password_expiration_table, foreign_key: password_expiration_id_column }
35
- when :single_session
36
- list << { name: :session_key, type: :one, table: single_session_table, foreign_key: single_session_id_column }
37
- when :otp
38
- list << { name: :otp_key, type: :one, table: otp_keys_table, foreign_key: otp_keys_id_column }
39
- when :sms_codes
40
- list << { name: :sms_code, type: :one, table: sms_codes_table, foreign_key: sms_id_column }
41
- when :recovery_codes
42
- list << { name: :recovery_codes, type: :many, table: recovery_codes_table, foreign_key: recovery_codes_id_column }
43
- when :webauthn
44
- list << { name: :webauthn_user_id, type: :one, table: webauthn_user_ids_table, foreign_key: webauthn_user_ids_account_id_column }
45
- list << { name: :webauthn_keys, type: :many, table: webauthn_keys_table, foreign_key: webauthn_keys_account_id_column }
46
- end
47
- end
48
-
49
- list
50
- end
51
- end
52
- end
53
- end
54
- end