mongoid-devise 1.0.1

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 (142) hide show
  1. data/CHANGELOG.rdoc +333 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +260 -0
  4. data/Rakefile +53 -0
  5. data/TODO +2 -0
  6. data/app/controllers/confirmations_controller.rb +33 -0
  7. data/app/controllers/passwords_controller.rb +42 -0
  8. data/app/controllers/registrations_controller.rb +55 -0
  9. data/app/controllers/sessions_controller.rb +45 -0
  10. data/app/controllers/unlocks_controller.rb +33 -0
  11. data/app/models/devise_mailer.rb +68 -0
  12. data/app/views/confirmations/new.html.erb +12 -0
  13. data/app/views/devise_mailer/confirmation_instructions.html.erb +5 -0
  14. data/app/views/devise_mailer/reset_password_instructions.html.erb +8 -0
  15. data/app/views/devise_mailer/unlock_instructions.html.erb +7 -0
  16. data/app/views/passwords/edit.html.erb +16 -0
  17. data/app/views/passwords/new.html.erb +12 -0
  18. data/app/views/registrations/edit.html.erb +25 -0
  19. data/app/views/registrations/new.html.erb +17 -0
  20. data/app/views/sessions/new.html.erb +17 -0
  21. data/app/views/shared/_devise_links.erb +19 -0
  22. data/app/views/unlocks/new.html.erb +12 -0
  23. data/generators/devise/USAGE +5 -0
  24. data/generators/devise/devise_generator.rb +15 -0
  25. data/generators/devise/lib/route_devise.rb +32 -0
  26. data/generators/devise/templates/migration.rb +23 -0
  27. data/generators/devise/templates/model.rb +9 -0
  28. data/generators/devise_install/USAGE +3 -0
  29. data/generators/devise_install/devise_install_generator.rb +15 -0
  30. data/generators/devise_install/templates/README +18 -0
  31. data/generators/devise_install/templates/devise.rb +102 -0
  32. data/generators/devise_views/USAGE +3 -0
  33. data/generators/devise_views/devise_views_generator.rb +21 -0
  34. data/init.rb +2 -0
  35. data/lib/devise.rb +253 -0
  36. data/lib/devise/controllers/helpers.rb +200 -0
  37. data/lib/devise/controllers/internal_helpers.rb +129 -0
  38. data/lib/devise/controllers/url_helpers.rb +41 -0
  39. data/lib/devise/encryptors/authlogic_sha512.rb +21 -0
  40. data/lib/devise/encryptors/base.rb +20 -0
  41. data/lib/devise/encryptors/bcrypt.rb +21 -0
  42. data/lib/devise/encryptors/clearance_sha1.rb +19 -0
  43. data/lib/devise/encryptors/restful_authentication_sha1.rb +22 -0
  44. data/lib/devise/encryptors/sha1.rb +27 -0
  45. data/lib/devise/encryptors/sha512.rb +27 -0
  46. data/lib/devise/failure_app.rb +65 -0
  47. data/lib/devise/hooks/activatable.rb +15 -0
  48. data/lib/devise/hooks/rememberable.rb +30 -0
  49. data/lib/devise/hooks/timeoutable.rb +18 -0
  50. data/lib/devise/hooks/trackable.rb +18 -0
  51. data/lib/devise/locales/en.yml +35 -0
  52. data/lib/devise/mapping.rb +131 -0
  53. data/lib/devise/models.rb +112 -0
  54. data/lib/devise/models/activatable.rb +16 -0
  55. data/lib/devise/models/authenticatable.rb +146 -0
  56. data/lib/devise/models/confirmable.rb +172 -0
  57. data/lib/devise/models/http_authenticatable.rb +21 -0
  58. data/lib/devise/models/lockable.rb +160 -0
  59. data/lib/devise/models/recoverable.rb +80 -0
  60. data/lib/devise/models/registerable.rb +8 -0
  61. data/lib/devise/models/rememberable.rb +94 -0
  62. data/lib/devise/models/timeoutable.rb +28 -0
  63. data/lib/devise/models/token_authenticatable.rb +89 -0
  64. data/lib/devise/models/trackable.rb +16 -0
  65. data/lib/devise/models/validatable.rb +48 -0
  66. data/lib/devise/orm/active_record.rb +41 -0
  67. data/lib/devise/orm/data_mapper.rb +83 -0
  68. data/lib/devise/orm/mongo_mapper.rb +51 -0
  69. data/lib/devise/orm/mongoid.rb +60 -0
  70. data/lib/devise/rails.rb +14 -0
  71. data/lib/devise/rails/routes.rb +125 -0
  72. data/lib/devise/rails/warden_compat.rb +25 -0
  73. data/lib/devise/schema.rb +65 -0
  74. data/lib/devise/strategies/authenticatable.rb +36 -0
  75. data/lib/devise/strategies/base.rb +16 -0
  76. data/lib/devise/strategies/http_authenticatable.rb +49 -0
  77. data/lib/devise/strategies/rememberable.rb +37 -0
  78. data/lib/devise/strategies/token_authenticatable.rb +37 -0
  79. data/lib/devise/test_helpers.rb +86 -0
  80. data/lib/devise/version.rb +3 -0
  81. data/test/controllers/helpers_test.rb +177 -0
  82. data/test/controllers/internal_helpers_test.rb +55 -0
  83. data/test/controllers/url_helpers_test.rb +47 -0
  84. data/test/devise_test.rb +69 -0
  85. data/test/encryptors_test.rb +31 -0
  86. data/test/failure_app_test.rb +44 -0
  87. data/test/integration/authenticatable_test.rb +271 -0
  88. data/test/integration/confirmable_test.rb +97 -0
  89. data/test/integration/http_authenticatable_test.rb +44 -0
  90. data/test/integration/lockable_test.rb +83 -0
  91. data/test/integration/recoverable_test.rb +141 -0
  92. data/test/integration/registerable_test.rb +130 -0
  93. data/test/integration/rememberable_test.rb +63 -0
  94. data/test/integration/timeoutable_test.rb +68 -0
  95. data/test/integration/token_authenticatable_test.rb +55 -0
  96. data/test/integration/trackable_test.rb +64 -0
  97. data/test/mailers/confirmation_instructions_test.rb +80 -0
  98. data/test/mailers/reset_password_instructions_test.rb +68 -0
  99. data/test/mailers/unlock_instructions_test.rb +62 -0
  100. data/test/mapping_test.rb +153 -0
  101. data/test/models/authenticatable_test.rb +180 -0
  102. data/test/models/confirmable_test.rb +228 -0
  103. data/test/models/lockable_test.rb +202 -0
  104. data/test/models/recoverable_test.rb +138 -0
  105. data/test/models/rememberable_test.rb +135 -0
  106. data/test/models/timeoutable_test.rb +28 -0
  107. data/test/models/token_authenticatable_test.rb +51 -0
  108. data/test/models/trackable_test.rb +5 -0
  109. data/test/models/validatable_test.rb +106 -0
  110. data/test/models_test.rb +56 -0
  111. data/test/orm/active_record.rb +31 -0
  112. data/test/orm/mongo_mapper.rb +20 -0
  113. data/test/orm/mongoid.rb +22 -0
  114. data/test/rails_app/app/active_record/admin.rb +7 -0
  115. data/test/rails_app/app/active_record/user.rb +7 -0
  116. data/test/rails_app/app/controllers/admins_controller.rb +6 -0
  117. data/test/rails_app/app/controllers/application_controller.rb +10 -0
  118. data/test/rails_app/app/controllers/home_controller.rb +4 -0
  119. data/test/rails_app/app/controllers/users_controller.rb +16 -0
  120. data/test/rails_app/app/helpers/application_helper.rb +3 -0
  121. data/test/rails_app/app/mongo_mapper/admin.rb +9 -0
  122. data/test/rails_app/app/mongo_mapper/user.rb +8 -0
  123. data/test/rails_app/app/mongoid/admin.rb +9 -0
  124. data/test/rails_app/app/mongoid/user.rb +8 -0
  125. data/test/rails_app/config/boot.rb +110 -0
  126. data/test/rails_app/config/environment.rb +42 -0
  127. data/test/rails_app/config/environments/development.rb +17 -0
  128. data/test/rails_app/config/environments/production.rb +28 -0
  129. data/test/rails_app/config/environments/test.rb +28 -0
  130. data/test/rails_app/config/initializers/devise.rb +79 -0
  131. data/test/rails_app/config/initializers/inflections.rb +2 -0
  132. data/test/rails_app/config/initializers/new_rails_defaults.rb +24 -0
  133. data/test/rails_app/config/initializers/session_store.rb +15 -0
  134. data/test/rails_app/config/routes.rb +21 -0
  135. data/test/routes_test.rb +110 -0
  136. data/test/support/assertions_helper.rb +37 -0
  137. data/test/support/integration_tests_helper.rb +71 -0
  138. data/test/support/test_silencer.rb +5 -0
  139. data/test/support/tests_helper.rb +39 -0
  140. data/test/test_helper.rb +21 -0
  141. data/test/test_helpers_test.rb +57 -0
  142. metadata +216 -0
@@ -0,0 +1,22 @@
1
+ require "digest/sha1"
2
+
3
+ module Devise
4
+ module Encryptors
5
+ # = RestfulAuthenticationSha1
6
+ # Simulates Restful Authentication's default encryption mechanism.
7
+ # Warning: it uses Devise's pepper to port the concept of REST_AUTH_SITE_KEY
8
+ # Warning: it uses Devise's stretches configuration to port the concept of REST_AUTH_DIGEST_STRETCHES. Should be set to 10 in
9
+ # the initializer to silumate the default behavior.
10
+ class RestfulAuthenticationSha1 < Base
11
+
12
+ # Gererates a default password digest based on salt, pepper and the
13
+ # incoming password.
14
+ def self.digest(password, stretches, salt, pepper)
15
+ digest = pepper
16
+ stretches.times { digest = Digest::SHA1.hexdigest([digest, salt, password, pepper].flatten.join('--')) }
17
+ digest
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ require "digest/sha1"
2
+
3
+ module Devise
4
+ module Encryptors
5
+ # = Sha1
6
+ # Uses the Sha1 hash algorithm to encrypt passwords.
7
+ class Sha1 < Base
8
+
9
+ # Gererates a default password digest based on stretches, salt, pepper and the
10
+ # incoming password.
11
+ def self.digest(password, stretches, salt, pepper)
12
+ digest = pepper
13
+ stretches.times { digest = self.secure_digest(salt, digest, password, pepper) }
14
+ digest
15
+ end
16
+
17
+ private
18
+
19
+ # Generate a SHA1 digest joining args. Generated token is something like
20
+ # --arg1--arg2--arg3--argN--
21
+ def self.secure_digest(*tokens)
22
+ ::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ require "digest/sha2"
2
+
3
+ module Devise
4
+ module Encryptors
5
+ # = Sha512
6
+ # Uses the Sha512 hash algorithm to encrypt passwords.
7
+ class Sha512 < Base
8
+
9
+ # Gererates a default password digest based on salt, pepper and the
10
+ # incoming password.
11
+ def self.digest(password, stretches, salt, pepper)
12
+ digest = pepper
13
+ stretches.times { digest = self.secure_digest(salt, digest, password, pepper) }
14
+ digest
15
+ end
16
+
17
+ private
18
+
19
+ # Generate a Sha512 digest joining args. Generated token is something like
20
+ # --arg1--arg2--arg3--argN--
21
+ def self.secure_digest(*tokens)
22
+ ::Digest::SHA512.hexdigest('--' << tokens.flatten.join('--') << '--')
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,65 @@
1
+ module Devise
2
+ # Failure application that will be called every time :warden is thrown from
3
+ # any strategy or hook. Responsible for redirect the user to the sign in
4
+ # page based on current scope and mapping. If no scope is given, redirect
5
+ # to the default_url.
6
+ class FailureApp
7
+ attr_reader :env
8
+ include Warden::Mixins::Common
9
+
10
+ cattr_accessor :default_url, :default_message, :instance_writer => false
11
+ @@default_message = :unauthenticated
12
+
13
+ def self.call(env)
14
+ new(env).respond!
15
+ end
16
+
17
+ def initialize(env)
18
+ @env = env
19
+ end
20
+
21
+ def respond!
22
+ options = @env['warden.options']
23
+ scope = options[:scope]
24
+
25
+ redirect_path = if mapping = Devise.mappings[scope]
26
+ "#{mapping.parsed_path}/#{mapping.path_names[:sign_in]}"
27
+ else
28
+ "/#{default_url}"
29
+ end
30
+ query_string = query_string_for(options)
31
+ store_location!(scope)
32
+
33
+ headers = {}
34
+ headers["Location"] = redirect_path
35
+ headers["Location"] << "?" << query_string unless query_string.empty?
36
+ headers["Content-Type"] = 'text/plain'
37
+
38
+ [302, headers, ["You are being redirected to #{redirect_path}"]]
39
+ end
40
+
41
+ # Build the proper query string based on the given message.
42
+ def query_string_for(options)
43
+ message = @env['warden'].try(:message) || options[:message] || default_message
44
+
45
+ params = case message
46
+ when Symbol
47
+ { message => true }
48
+ when String
49
+ { :message => message }
50
+ else
51
+ {}
52
+ end
53
+
54
+ Rack::Utils.build_query(params)
55
+ end
56
+
57
+ # Stores requested uri to redirect the user after signing in. We cannot use
58
+ # scoped session provided by warden here, since the user is not authenticated
59
+ # yet, but we still need to store the uri based on scope, so different scopes
60
+ # would never use the same uri to redirect.
61
+ def store_location!(scope)
62
+ session[:"#{scope}.return_to"] = request.request_uri if request && request.get?
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,15 @@
1
+ # Deny user access whenever his account is not active yet.
2
+ Warden::Manager.after_set_user do |record, warden, options|
3
+ if record && record.respond_to?(:active?) && !record.active?
4
+ scope = options[:scope]
5
+ warden.logout(scope)
6
+
7
+ # If winning strategy was set, this is being called after authenticate and
8
+ # there is no need to force a redirect.
9
+ if warden.winning_strategy
10
+ warden.winning_strategy.fail!(record.inactive_message)
11
+ else
12
+ throw :warden, :scope => scope, :message => record.inactive_message
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,30 @@
1
+ # After authenticate hook to verify if the user in the given scope asked to be
2
+ # remembered while he does not sign out. Generates a new remember token for
3
+ # that specific user and adds a cookie with this user info to sign in this user
4
+ # automatically without asking for credentials. Refer to rememberable strategy
5
+ # for more info.
6
+ Warden::Manager.after_authentication do |record, warden, options|
7
+ scope = options[:scope]
8
+ remember_me = warden.params[scope].try(:fetch, :remember_me, nil)
9
+
10
+ if Devise::TRUE_VALUES.include?(remember_me) &&
11
+ warden.authenticated?(scope) && record.respond_to?(:remember_me!)
12
+ record.remember_me!
13
+
14
+ warden.response.set_cookie "remember_#{scope}_token", {
15
+ :value => record.class.serialize_into_cookie(record),
16
+ :expires => record.remember_expires_at,
17
+ :path => "/"
18
+ }
19
+ end
20
+ end
21
+
22
+ # Before logout hook to forget the user in the given scope, only if rememberable
23
+ # is activated for this scope. Also clear remember token to ensure the user
24
+ # won't be remembered again.
25
+ Warden::Manager.before_logout do |record, warden, scope|
26
+ if record.respond_to?(:forget_me!)
27
+ record.forget_me!
28
+ warden.response.delete_cookie "remember_#{scope}_token"
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ # Each time a record is set we check whether it's session has already timed out
2
+ # or not, based on last request time. If so, the record is logged out and
3
+ # redirected to the sign in page. Also, each time the request comes and the
4
+ # record is set, we set the last request time inside it's scoped session to
5
+ # verify timeout in the following request.
6
+ Warden::Manager.after_set_user do |record, warden, options|
7
+ scope = options[:scope]
8
+ if record && record.respond_to?(:timedout?) && warden.authenticated?(scope)
9
+ last_request_at = warden.session(scope)['last_request_at']
10
+
11
+ if record.timedout?(last_request_at)
12
+ warden.logout(scope)
13
+ throw :warden, :scope => scope, :message => :timeout
14
+ end
15
+
16
+ warden.session(scope)['last_request_at'] = Time.now.utc
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # After each sign in, update sign in time, sign in count and sign in IP.
2
+ Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
3
+ scope = options[:scope]
4
+ if Devise.mappings[scope].try(:trackable?) && warden.authenticated?(scope)
5
+ old_current, new_current = record.current_sign_in_at, Time.now
6
+ record.last_sign_in_at = old_current || new_current
7
+ record.current_sign_in_at = new_current
8
+
9
+ old_current, new_current = record.current_sign_in_ip, warden.request.remote_ip
10
+ record.last_sign_in_ip = old_current || new_current
11
+ record.current_sign_in_ip = new_current
12
+
13
+ record.sign_in_count ||= 0
14
+ record.sign_in_count += 1
15
+
16
+ record.save(false)
17
+ end
18
+ end
@@ -0,0 +1,35 @@
1
+ en:
2
+ devise:
3
+ sessions:
4
+ link: 'Sign in'
5
+ signed_in: 'Signed in successfully.'
6
+ signed_out: 'Signed out successfully.'
7
+ unauthenticated: 'You need to sign in or sign up before continuing.'
8
+ unconfirmed: 'You have to confirm your account before continuing.'
9
+ locked: 'Your account is locked.'
10
+ invalid: 'Invalid email or password.'
11
+ invalid_token: 'Invalid authentication token.'
12
+ timeout: 'Your session expired, please sign in again to continue.'
13
+ inactive: 'Your account was not activated yet.'
14
+ passwords:
15
+ link: 'Forgot password?'
16
+ send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
17
+ updated: 'Your password was changed successfully. You are now signed in.'
18
+ confirmations:
19
+ link: "Didn't receive confirmation instructions?"
20
+ send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
21
+ confirmed: 'Your account was successfully confirmed. You are now signed in.'
22
+ registrations:
23
+ link: 'Sign up'
24
+ signed_up: 'You have signed up successfully.'
25
+ updated: 'You updated your account successfully.'
26
+ destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
27
+ unlocks:
28
+ link: "Didn't receive unlock instructions?"
29
+ send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
30
+ unlocked: 'Your account was successfully unlocked. You are now signed in.'
31
+ mailer:
32
+ confirmation_instructions: 'Confirmation instructions'
33
+ reset_password_instructions: 'Reset password instructions'
34
+ unlock_instructions: 'Unlock Instructions'
35
+
@@ -0,0 +1,131 @@
1
+ module Devise
2
+ # Responsible for handling devise mappings and routes configuration. Each
3
+ # resource configured by devise_for in routes is actually creating a mapping
4
+ # object. You can refer to devise_for in routes for usage options.
5
+ #
6
+ # The required value in devise_for is actually not used internally, but it's
7
+ # inflected to find all other values.
8
+ #
9
+ # map.devise_for :users
10
+ # mapping = Devise.mappings[:user]
11
+ #
12
+ # mapping.name #=> :user
13
+ # # is the scope used in controllers and warden, given in the route as :singular.
14
+ #
15
+ # mapping.as #=> "users"
16
+ # # how the mapping should be search in the path, given in the route as :as.
17
+ #
18
+ # mapping.to #=> User
19
+ # # is the class to be loaded from routes, given in the route as :class_name.
20
+ #
21
+ # mapping.for #=> [:authenticatable]
22
+ # # is the modules included in the class
23
+ #
24
+ class Mapping #:nodoc:
25
+ attr_reader :name, :as, :path_names, :path_prefix, :route_options
26
+
27
+ # Loop through all mappings looking for a map that matches with the requested
28
+ # path (ie /users/sign_in). If a path prefix is given, it's taken into account.
29
+ def self.find_by_path(path)
30
+ Devise.mappings.each_value do |mapping|
31
+ route = path.split("/")[mapping.as_position]
32
+ return mapping if route && mapping.as == route.to_sym
33
+ end
34
+ nil
35
+ end
36
+
37
+ # Find a mapping by a given class. It takes into account single table inheritance as well.
38
+ def self.find_by_class(klass)
39
+ Devise.mappings.each_value do |mapping|
40
+ return mapping if klass <= mapping.to
41
+ end
42
+ nil
43
+ end
44
+
45
+ # Receives an object and find a scope for it. If a scope cannot be found,
46
+ # raises an error. If a symbol is given, it's considered to be the scope.
47
+ def self.find_scope!(duck)
48
+ case duck
49
+ when String, Symbol
50
+ duck
51
+ else
52
+ klass = duck.is_a?(Class) ? duck : duck.class
53
+ mapping = Devise::Mapping.find_by_class(klass)
54
+ raise "Could not find a valid mapping for #{duck}" unless mapping
55
+ mapping.name
56
+ end
57
+ end
58
+
59
+ # Default url options which can be used as prefix.
60
+ def self.default_url_options
61
+ {}
62
+ end
63
+
64
+ def initialize(name, options) #:nodoc:
65
+ @as = (options.delete(:as) || name).to_sym
66
+ @klass = (options.delete(:class_name) || name.to_s.classify).to_s
67
+ @name = (options.delete(:scope) || name.to_s.singularize).to_sym
68
+
69
+ @path_prefix = "/#{options.delete(:path_prefix)}/".squeeze("/")
70
+ @route_options = options || {}
71
+
72
+ @path_names = Hash.new { |h,k| h[k] = k.to_s }
73
+ @path_names.merge!(options.delete(:path_names) || {})
74
+ end
75
+
76
+ # Return modules for the mapping.
77
+ def for
78
+ @for ||= to.devise_modules
79
+ end
80
+
81
+ # Reload mapped class each time when cache_classes is false.
82
+ def to
83
+ return @to if @to
84
+ klass = @klass.constantize
85
+ @to = klass if Rails.configuration.cache_classes
86
+ klass
87
+ end
88
+
89
+ # Check if the respective controller has a module in the mapping class.
90
+ def allows?(controller)
91
+ (self.for & CONTROLLERS[controller.to_sym]).present?
92
+ end
93
+
94
+ # Return in which position in the path prefix devise should find the as mapping.
95
+ def as_position
96
+ self.path_prefix.count("/")
97
+ end
98
+
99
+ # Returns the raw path using path_prefix and as.
100
+ def raw_path
101
+ path_prefix + as.to_s
102
+ end
103
+
104
+ # Returns the parsed path taking into account the relative url root and raw path.
105
+ def parsed_path
106
+ returning (ActionController::Base.relative_url_root.to_s + raw_path) do |path|
107
+ self.class.default_url_options.each do |key, value|
108
+ path.gsub!(key.inspect, value.to_param)
109
+ end
110
+ end
111
+ end
112
+
113
+ # Create magic predicates for verifying what module is activated by this map.
114
+ # Example:
115
+ #
116
+ # def confirmable?
117
+ # self.for.include?(:confirmable)
118
+ # end
119
+ #
120
+ def self.register(*modules)
121
+ modules.each do |m|
122
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
123
+ def #{m}?
124
+ self.for.include?(:#{m})
125
+ end
126
+ METHOD
127
+ end
128
+ end
129
+ Devise::Mapping.register *ALL
130
+ end
131
+ end
@@ -0,0 +1,112 @@
1
+ module Devise
2
+ module Models
3
+ autoload :Activatable, 'devise/models/activatable'
4
+ autoload :Authenticatable, 'devise/models/authenticatable'
5
+ autoload :Confirmable, 'devise/models/confirmable'
6
+ autoload :Lockable, 'devise/models/lockable'
7
+ autoload :Recoverable, 'devise/models/recoverable'
8
+ autoload :Rememberable, 'devise/models/rememberable'
9
+ autoload :Registerable, 'devise/models/registerable'
10
+ autoload :Timeoutable, 'devise/models/timeoutable'
11
+ autoload :Trackable, 'devise/models/trackable'
12
+ autoload :Validatable, 'devise/models/validatable'
13
+
14
+ # Creates configuration values for Devise and for the given module.
15
+ #
16
+ # Devise::Models.config(Devise::Authenticable, :stretches, 10)
17
+ #
18
+ # The line above creates:
19
+ #
20
+ # 1) An accessor called Devise.stretches, which value is used by default;
21
+ #
22
+ # 2) Some class methods for your model Model.stretches and Model.stretches=
23
+ # which have higher priority than Devise.stretches;
24
+ #
25
+ # 3) And an instance method stretches.
26
+ #
27
+ # To add the class methods you need to have a module ClassMethods defined
28
+ # inside the given class.
29
+ #
30
+ def self.config(mod, *accessors) #:nodoc:
31
+ accessors.each do |accessor|
32
+ mod.class_eval <<-METHOD, __FILE__, __LINE__ + 1
33
+ def #{accessor}
34
+ if defined?(@#{accessor})
35
+ @#{accessor}
36
+ elsif superclass.respond_to?(:#{accessor})
37
+ superclass.#{accessor}
38
+ else
39
+ Devise.#{accessor}
40
+ end
41
+ end
42
+
43
+ def #{accessor}=(value)
44
+ @#{accessor} = value
45
+ end
46
+ METHOD
47
+ end
48
+ end
49
+
50
+ # Include the chosen devise modules in your model:
51
+ #
52
+ # devise :authenticatable, :confirmable, :recoverable
53
+ #
54
+ # You can also give any of the devise configuration values in form of a hash,
55
+ # with specific values for this model. Please check your Devise initializer
56
+ # for a complete description on those values.
57
+ #
58
+ def devise(*modules)
59
+ raise "You need to give at least one Devise module" if modules.empty?
60
+ options = modules.extract_options!
61
+
62
+ @devise_modules = Devise::ALL & modules.map(&:to_sym).uniq
63
+
64
+ Devise.orm_class.included_modules_hook(self) do
65
+ devise_modules.each do |m|
66
+ include Devise::Models.const_get(m.to_s.classify)
67
+ end
68
+
69
+ options.each { |key, value| send(:"#{key}=", value) }
70
+ end
71
+ end
72
+
73
+ # Stores all modules included inside the model, so we are able to verify
74
+ # which routes are needed.
75
+ def devise_modules
76
+ @devise_modules ||= []
77
+ end
78
+
79
+ # Find an initialize a record setting an error if it can't be found.
80
+ def find_or_initialize_with_error_by(attribute, value, error=:invalid)
81
+ if value.present?
82
+ conditions = { attribute => value }
83
+ record = find(:first, :conditions => conditions)
84
+ end
85
+
86
+ unless record
87
+ record = new
88
+
89
+ if value.present?
90
+ record.send(:"#{attribute}=", value)
91
+ else
92
+ error, skip_default = :blank, true
93
+ end
94
+
95
+ add_error_on(record, attribute, error, !skip_default)
96
+ end
97
+
98
+ record
99
+ end
100
+
101
+ # Wraps add error logic in a method that works for different frameworks.
102
+ def add_error_on(record, attribute, error, add_default=true)
103
+ options = add_default ? { :default => error.to_s.gsub("_", " ") } : {}
104
+
105
+ begin
106
+ record.errors.add(attribute, error, options)
107
+ rescue ArgumentError
108
+ record.errors.add(attribute, error.to_s.gsub("_", " "))
109
+ end
110
+ end
111
+ end
112
+ end