devise-multi_email 1.0.5 → 2.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.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -1
  3. data/CHANGELOG.md +15 -2
  4. data/Gemfile +2 -9
  5. data/README.md +69 -18
  6. data/devise-multi_email.gemspec +4 -0
  7. data/examples/rails5_app/.gitignore +21 -0
  8. data/examples/rails5_app/Gemfile +55 -0
  9. data/examples/rails5_app/Gemfile.lock +185 -0
  10. data/examples/rails5_app/README.md +24 -0
  11. data/examples/rails5_app/Rakefile +6 -0
  12. data/examples/rails5_app/app/assets/config/manifest.js +3 -0
  13. data/examples/rails5_app/app/assets/images/.keep +0 -0
  14. data/examples/rails5_app/app/assets/javascripts/application.js +16 -0
  15. data/examples/rails5_app/app/assets/javascripts/cable.js +13 -0
  16. data/examples/rails5_app/app/assets/javascripts/channels/.keep +0 -0
  17. data/examples/rails5_app/app/assets/stylesheets/application.css +15 -0
  18. data/examples/rails5_app/app/channels/application_cable/channel.rb +4 -0
  19. data/examples/rails5_app/app/channels/application_cable/connection.rb +4 -0
  20. data/examples/rails5_app/app/controllers/application_controller.rb +3 -0
  21. data/examples/rails5_app/app/controllers/concerns/.keep +0 -0
  22. data/examples/rails5_app/app/helpers/application_helper.rb +2 -0
  23. data/examples/rails5_app/app/jobs/application_job.rb +2 -0
  24. data/examples/rails5_app/app/mailers/application_mailer.rb +4 -0
  25. data/examples/rails5_app/app/models/application_record.rb +3 -0
  26. data/examples/rails5_app/app/models/concerns/.keep +0 -0
  27. data/examples/rails5_app/app/models/email.rb +3 -0
  28. data/examples/rails5_app/app/models/user.rb +9 -0
  29. data/examples/rails5_app/app/views/layouts/application.html.erb +14 -0
  30. data/examples/rails5_app/app/views/layouts/mailer.html.erb +13 -0
  31. data/examples/rails5_app/app/views/layouts/mailer.text.erb +1 -0
  32. data/examples/rails5_app/bin/bundle +3 -0
  33. data/examples/rails5_app/bin/rails +4 -0
  34. data/examples/rails5_app/bin/rake +4 -0
  35. data/examples/rails5_app/bin/setup +34 -0
  36. data/examples/rails5_app/bin/update +29 -0
  37. data/examples/rails5_app/config/application.rb +15 -0
  38. data/examples/rails5_app/config/boot.rb +3 -0
  39. data/examples/rails5_app/config/cable.yml +9 -0
  40. data/examples/rails5_app/config/database.yml +25 -0
  41. data/examples/rails5_app/config/environment.rb +5 -0
  42. data/examples/rails5_app/config/environments/development.rb +56 -0
  43. data/examples/rails5_app/config/environments/production.rb +86 -0
  44. data/examples/rails5_app/config/environments/test.rb +42 -0
  45. data/examples/rails5_app/config/initializers/application_controller_renderer.rb +6 -0
  46. data/examples/rails5_app/config/initializers/assets.rb +11 -0
  47. data/examples/rails5_app/config/initializers/backtrace_silencers.rb +7 -0
  48. data/examples/rails5_app/config/initializers/cookies_serializer.rb +5 -0
  49. data/examples/rails5_app/config/initializers/devise.rb +274 -0
  50. data/examples/rails5_app/config/initializers/filter_parameter_logging.rb +4 -0
  51. data/examples/rails5_app/config/initializers/inflections.rb +16 -0
  52. data/examples/rails5_app/config/initializers/mime_types.rb +4 -0
  53. data/examples/rails5_app/config/initializers/new_framework_defaults.rb +24 -0
  54. data/examples/rails5_app/config/initializers/session_store.rb +3 -0
  55. data/examples/rails5_app/config/initializers/wrap_parameters.rb +14 -0
  56. data/examples/rails5_app/config/locales/devise.en.yml +62 -0
  57. data/examples/rails5_app/config/locales/en.yml +23 -0
  58. data/examples/rails5_app/config/puma.rb +47 -0
  59. data/examples/rails5_app/config/routes.rb +4 -0
  60. data/examples/rails5_app/config/secrets.yml +22 -0
  61. data/examples/rails5_app/config/spring.rb +6 -0
  62. data/examples/rails5_app/config.ru +5 -0
  63. data/examples/rails5_app/db/migrate/20170307140813_devise_create_users.rb +49 -0
  64. data/examples/rails5_app/db/migrate/20170307145547_add_password_salt_to_users.rb +5 -0
  65. data/examples/rails5_app/db/schema.rb +44 -0
  66. data/examples/rails5_app/db/seeds.rb +7 -0
  67. data/examples/rails5_app/lib/assets/.keep +0 -0
  68. data/examples/rails5_app/lib/tasks/.keep +0 -0
  69. data/examples/rails5_app/log/.keep +0 -0
  70. data/examples/rails5_app/public/404.html +67 -0
  71. data/examples/rails5_app/public/422.html +67 -0
  72. data/examples/rails5_app/public/500.html +66 -0
  73. data/examples/rails5_app/public/apple-touch-icon-precomposed.png +0 -0
  74. data/examples/rails5_app/public/apple-touch-icon.png +0 -0
  75. data/examples/rails5_app/public/favicon.ico +0 -0
  76. data/examples/rails5_app/public/robots.txt +5 -0
  77. data/examples/rails5_app/test/controllers/.keep +0 -0
  78. data/examples/rails5_app/test/fixtures/.keep +0 -0
  79. data/examples/rails5_app/test/fixtures/files/.keep +0 -0
  80. data/examples/rails5_app/test/helpers/.keep +0 -0
  81. data/examples/rails5_app/test/integration/.keep +0 -0
  82. data/examples/rails5_app/test/mailers/.keep +0 -0
  83. data/examples/rails5_app/test/models/.keep +0 -0
  84. data/examples/rails5_app/test/test_helper.rb +10 -0
  85. data/examples/rails5_app/tmp/.keep +0 -0
  86. data/examples/rails5_app/vendor/assets/javascripts/.keep +0 -0
  87. data/examples/rails5_app/vendor/assets/stylesheets/.keep +0 -0
  88. data/gemfiles/rails_4_2.gemfile +5 -0
  89. data/gemfiles/rails_5_0.gemfile +5 -0
  90. data/gemfiles/rails_5_1.gemfile +5 -0
  91. data/lib/devise/multi_email/association_manager.rb +30 -0
  92. data/lib/devise/multi_email/email_model_extensions.rb +20 -0
  93. data/lib/devise/multi_email/email_model_manager.rb +18 -0
  94. data/lib/devise/multi_email/models/authenticatable.rb +23 -44
  95. data/lib/devise/multi_email/models/confirmable.rb +20 -21
  96. data/lib/devise/multi_email/models/validatable.rb +42 -38
  97. data/lib/devise/multi_email/parent_model_extensions.rb +27 -0
  98. data/lib/devise/multi_email/parent_model_manager.rb +55 -0
  99. data/lib/devise/multi_email/version.rb +1 -1
  100. data/lib/devise/multi_email.rb +32 -0
  101. metadata +147 -2
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body>
58
+ <!-- This file lives in public/404.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>The page you were looking for doesn't exist.</h1>
62
+ <p>You may have mistyped the address or the page may have moved.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body>
58
+ <!-- This file lives in public/422.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>The change you wanted was rejected.</h1>
62
+ <p>Maybe you tried to change something you didn't have access to.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,66 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body>
58
+ <!-- This file lives in public/500.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>We're sorry, but something went wrong.</h1>
62
+ </div>
63
+ <p>If you are the application owner check the logs for more information.</p>
64
+ </div>
65
+ </body>
66
+ </html>
File without changes
File without changes
@@ -0,0 +1,5 @@
1
+ # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2
+ #
3
+ # To ban all spiders from the entire site uncomment the next two lines:
4
+ # User-agent: *
5
+ # Disallow: /
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,10 @@
1
+ ENV['RAILS_ENV'] ||= 'test'
2
+ require File.expand_path('../../config/environment', __FILE__)
3
+ require 'rails/test_help'
4
+
5
+ class ActiveSupport::TestCase
6
+ # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
7
+ fixtures :all
8
+
9
+ # Add more helper methods to be used by all tests here...
10
+ end
File without changes
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 4.2.8"
4
+
5
+ gemspec path: "../"
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 5.0.3"
4
+
5
+ gemspec path: "../"
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 5.1.1"
4
+
5
+ gemspec path: "../"
@@ -0,0 +1,30 @@
1
+
2
+ module Devise
3
+ module MultiEmail
4
+ class AssociationManager
5
+
6
+ attr_reader :name
7
+
8
+ def initialize(klass, association_name)
9
+ @klass = klass
10
+ @name = association_name
11
+ end
12
+
13
+ def include_module(mod)
14
+ model_class.__send__ :include, mod
15
+ end
16
+
17
+ def model_class
18
+ unless reflection
19
+ raise "#{@klass}##{name} association not found: It might be because your declaration is after `devise :multi_email_confirmable`."
20
+ end
21
+
22
+ @model_class ||= reflection.class_name.constantize
23
+ end
24
+
25
+ def reflection
26
+ @reflection ||= @klass.reflect_on_association(name)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,20 @@
1
+ require 'devise/multi_email/association_manager'
2
+ require 'devise/multi_email/email_model_manager'
3
+
4
+ module Devise
5
+ module MultiEmail
6
+ module EmailModelExtensions
7
+ extend ActiveSupport::Concern
8
+
9
+ def multi_email
10
+ @multi_email ||= EmailModelManager.new(self)
11
+ end
12
+
13
+ module ClassMethods
14
+ def multi_email_association
15
+ @multi_email ||= AssociationManager.new(self, Devise::MultiEmail.parent_association_name)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ require 'devise/multi_email/email_model_extensions'
2
+
3
+ module Devise
4
+ module MultiEmail
5
+ class EmailModelManager
6
+
7
+ attr_reader :record
8
+
9
+ def initialize(record)
10
+ @record = record
11
+ end
12
+
13
+ def parent
14
+ record.__send__(record.class.multi_email_association.name)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,59 +1,47 @@
1
+ require 'devise/multi_email/parent_model_extensions'
2
+
1
3
  module Devise
2
4
  module Models
3
5
  module EmailAuthenticatable
4
- USER_ASSOCIATION = :user
5
-
6
6
  def devise_scope
7
- user_association = self.class.reflect_on_association(USER_ASSOCIATION)
8
- if user_association
9
- user_association.class_name.constantize
10
- else
11
- raise "#{self.class.name}: Association :#{USER_ASSOCIATION} not found: Have you declared that ?"
12
- end
7
+ self.class.multi_email_association.model_class
13
8
  end
14
9
  end
15
10
 
16
11
  module MultiEmailAuthenticatable
17
12
  extend ActiveSupport::Concern
18
- EMAILS_ASSOCIATION = :emails
19
13
 
20
14
  included do
21
- devise :database_authenticatable
15
+ include Devise::MultiEmail::ParentModelExtensions
22
16
 
23
17
  attr_accessor :current_login_email
24
18
 
25
- email_class.send :include, EmailAuthenticatable
19
+ devise :database_authenticatable
20
+
21
+ include AuthenticatableExtensions
26
22
  end
27
23
 
28
24
  def self.required_fields(klass)
29
25
  []
30
26
  end
31
27
 
32
- # Gets the primary email record.
33
- def primary_email_record
34
- valid_emails = emails.each.select do |email_record|
35
- !email_record.destroyed? && !email_record.marked_for_destruction?
28
+ module AuthenticatableExtensions
29
+ extend ActiveSupport::Concern
30
+
31
+ included do
32
+ multi_email_association.include_module(EmailAuthenticatable)
36
33
  end
37
34
 
38
- result = valid_emails.find(&:primary?)
39
- result ||= valid_emails.first
40
- result
41
- end
35
+ delegate :skip_confirmation!, to: Devise::MultiEmail.primary_email_method_name, allow_nil: false
42
36
 
43
- # Gets the primary email address of the user.
44
- def email
45
- primary_email_record.try(:email)
46
- end
37
+ # Gets the primary email address of the user.
38
+ def email
39
+ multi_email.primary_email.try(:email)
40
+ end
47
41
 
48
- # Sets the default email address of the user.
49
- def email=(email)
50
- record = primary_email_record
51
- if email
52
- record ||= emails.build
53
- record.email = email
54
- record.primary = true
55
- elsif email.nil? && record
56
- record.mark_for_destruction
42
+ # Sets the default email address of the user.
43
+ def email=(new_email)
44
+ multi_email.change_primary_email_to(new_email)
57
45
  end
58
46
  end
59
47
 
@@ -64,9 +52,9 @@ module Devise
64
52
 
65
53
  if email && email.is_a?(String)
66
54
  conditions = filtered_conditions.to_h.merge(opts).
67
- reverse_merge(emails: { email: email })
55
+ reverse_merge(multi_email_association.reflection.table_name => { email: email })
68
56
 
69
- resource = joins(:emails).find_by(conditions)
57
+ resource = joins(multi_email_association.name).find_by(conditions)
70
58
  resource.current_login_email = email if resource.respond_to?(:current_login_email=)
71
59
  resource
72
60
  else
@@ -74,17 +62,8 @@ module Devise
74
62
  end
75
63
  end
76
64
 
77
- def email_class
78
- email_association = reflect_on_association(EMAILS_ASSOCIATION)
79
- if email_association
80
- email_association.class_name.constantize
81
- else
82
- raise "#{self.class.name}: Association :#{EMAILS_ASSOCIATION} not found: It might because your declaration is after `devise :multi_email_confirmable`."
83
- end
84
- end
85
-
86
65
  def find_by_email(email)
87
- joins(:emails).where(emails: {email: email.downcase}).first
66
+ joins(multi_email_association.name).where(multi_email_association.reflection.table_name => { email: email.downcase }).first
88
67
  end
89
68
  end
90
69
  end
@@ -1,3 +1,5 @@
1
+ require 'devise/multi_email/parent_model_extensions'
2
+
1
3
  module Devise
2
4
  module Models
3
5
  module EmailConfirmable
@@ -11,7 +13,7 @@ module Devise
11
13
 
12
14
  module ClassReplacementMethods
13
15
  def allow_unconfirmed_access_for
14
- 0.day
16
+ 0.days
15
17
  end
16
18
  end
17
19
  end
@@ -20,18 +22,25 @@ module Devise
20
22
  extend ActiveSupport::Concern
21
23
 
22
24
  included do
25
+ include Devise::MultiEmail::ParentModelExtensions
26
+
23
27
  devise :confirmable
24
- include InstanceReplacementMethods
25
- extend ClassReplacementMethods
26
28
 
27
- email_class.send :include, EmailConfirmable
29
+ include ConfirmableExtensions
28
30
  end
29
31
 
30
32
  def self.required_fields(klass)
31
33
  []
32
34
  end
33
35
 
34
- module InstanceReplacementMethods
36
+ module ConfirmableExtensions
37
+ extend ActiveSupport::Concern
38
+
39
+ included do
40
+ multi_email_association.include_module(EmailConfirmable)
41
+ end
42
+
43
+ # delegate before creating overriding methods
35
44
  delegate :skip_confirmation!, :skip_confirmation_notification!, :skip_reconfirmation!, :confirmation_required?,
36
45
  :confirmation_token, :confirmed_at, :confirmation_sent_at, :confirm, :confirmed?, :unconfirmed_email,
37
46
  :reconfirmation_required?, :pending_reconfirmation?, to: :primary_email_record, allow_nil: true
@@ -58,7 +67,7 @@ module Devise
58
67
  end
59
68
  end
60
69
 
61
- protected
70
+ protected
62
71
 
63
72
  # Overrides Devise::Models::Confirmable#postpone_email_change?
64
73
  def postpone_email_change?
@@ -77,28 +86,18 @@ module Devise
77
86
  def send_on_create_confirmation_instructions
78
87
  end
79
88
 
80
- private
89
+ private
81
90
 
82
91
  def current_login_email_record
83
92
  if respond_to?(:current_login_email) && current_login_email
84
- send(self.class::EMAILS_ASSOCIATION).find_by(email: current_login_email)
93
+ multi_email.emails.find_by(email: current_login_email)
85
94
  end
86
95
  end
87
- end
88
-
89
- module ClassReplacementMethods
90
- # Overrides Devise::Models::Confirmable.confirm_by_token
91
- # Forward the logic to email.
92
- def confirm_by_token(token)
93
- email_class.confirm_by_token(token)
94
- end
95
96
 
96
- # Overrides Devise::Models::Confirmable.send_confirmation_instructions
97
- # Forward the logic to email.
98
- def send_confirmation_instructions(params)
99
- email_class.send_confirmation_instructions(params)
97
+ module ClassMethods
98
+ delegate :confirm_by_token, :send_confirmation_instructions, to: 'multi_email_association.model_class', allow_nil: false
100
99
  end
101
100
  end
102
101
  end
103
102
  end
104
- end
103
+ end
@@ -1,14 +1,14 @@
1
+ require 'devise/multi_email/parent_model_extensions'
2
+
1
3
  module Devise
2
4
  module Models
3
5
  module EmailValidatable
4
- def self.included(base)
5
- base.extend ClassMethods
6
+ extend ActiveSupport::Concern
6
7
 
7
- base.class_eval do
8
- validates_presence_of :email, if: :email_required?
9
- validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
10
- validates_format_of :email, with: email_regexp, allow_blank: true, if: :email_changed?
11
- end
8
+ included do
9
+ validates_presence_of :email, if: :email_required?
10
+ validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
11
+ validates_format_of :email, with: email_regexp, allow_blank: true, if: :email_changed?
12
12
  end
13
13
 
14
14
  def email_required?
@@ -21,42 +21,31 @@ module Devise
21
21
  end
22
22
 
23
23
  module MultiEmailValidatable
24
- def self.required_fields(klass)
25
- []
26
- end
24
+ extend ActiveSupport::Concern
27
25
 
28
- # All validations used by this module.
29
- VALIDATIONS = [:validates_presence_of, :validates_uniqueness_of, :validates_format_of,
30
- :validates_confirmation_of, :validates_length_of].freeze
26
+ included do
27
+ include Devise::MultiEmail::ParentModelExtensions
31
28
 
32
- def self.included(base)
33
- base.extend ClassMethods
34
- assert_validations_api!(base)
29
+ assert_validations_api!(self)
35
30
 
36
- base.class_eval do
37
- validates_presence_of :email, if: :email_required?
31
+ validates_presence_of :email, if: :email_required?
38
32
 
39
- validates_presence_of :password, if: :password_required?
40
- validates_confirmation_of :password, if: :password_required?
41
- validates_length_of :password, within: password_length, allow_blank: true
33
+ validates_presence_of :password, if: :password_required?
34
+ validates_confirmation_of :password, if: :password_required?
35
+ validates_length_of :password, within: password_length, allow_blank: true
42
36
 
43
- after_validation :propagate_email_errors
44
- email_class.send :include, EmailValidatable
45
- end
37
+ after_validation :propagate_email_errors
46
38
 
47
- base.devise_modules << :validatable
48
- end
39
+ multi_email_association.include_module(EmailValidatable)
49
40
 
50
- def self.assert_validations_api!(base) #:nodoc:
51
- unavailable_validations = VALIDATIONS.select { |v| !base.respond_to?(v) }
41
+ devise_modules << :validatable
42
+ end
52
43
 
53
- unless unavailable_validations.empty?
54
- raise "Could not use :validatable module since #{base} does not respond " <<
55
- "to the following methods: #{unavailable_validations.to_sentence}."
56
- end
44
+ def self.required_fields(klass)
45
+ []
57
46
  end
58
47
 
59
- protected
48
+ protected
60
49
 
61
50
  # Same as Devise::Models::Validatable#password_required?
62
51
  def password_required?
@@ -68,15 +57,16 @@ module Devise
68
57
  true
69
58
  end
70
59
 
71
- private
60
+ private
72
61
 
73
62
  def propagate_email_errors
74
- email_error_key = self.class::EMAILS_ASSOCIATION
75
- if respond_to?("#{self.class::EMAILS_ASSOCIATION}_attributes=")
63
+ email_error_key = self.class.multi_email_association.name
64
+
65
+ if respond_to?("#{email_error_key}_attributes=")
76
66
  email_error_key = "#{email_error_key}.email".to_sym
77
67
  end
78
68
 
79
- return if (email_errors = errors.delete(email_error_key)).nil?
69
+ email_errors = errors.delete(email_error_key) || []
80
70
 
81
71
  email_errors.each do |error|
82
72
  errors.add(:email, error)
@@ -84,8 +74,22 @@ module Devise
84
74
  end
85
75
 
86
76
  module ClassMethods
77
+
78
+ # All validations used by this module.
79
+ VALIDATIONS = [:validates_presence_of, :validates_uniqueness_of, :validates_format_of,
80
+ :validates_confirmation_of, :validates_length_of].freeze
81
+
82
+ def assert_validations_api!(base) #:nodoc:
83
+ unavailable_validations = VALIDATIONS.select{ |v| !base.respond_to?(v) }
84
+
85
+ unless unavailable_validations.empty?
86
+ raise "Could not use :validatable module since #{base} does not respond " <<
87
+ "to the following methods: #{unavailable_validations.to_sentence}."
88
+ end
89
+ end
90
+
87
91
  Devise::Models.config(self, :password_length)
88
92
  end
89
93
  end
90
94
  end
91
- end
95
+ end