devise 1.1.pre4 → 1.1.rc0

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 (122) hide show
  1. data/CHANGELOG.rdoc +31 -2
  2. data/Gemfile +15 -6
  3. data/README.rdoc +12 -16
  4. data/Rakefile +2 -2
  5. data/TODO +2 -1
  6. data/app/controllers/devise/confirmations_controller.rb +1 -1
  7. data/app/controllers/devise/passwords_controller.rb +2 -3
  8. data/app/controllers/devise/registrations_controller.rb +5 -5
  9. data/app/controllers/devise/sessions_controller.rb +5 -27
  10. data/app/controllers/devise/unlocks_controller.rb +9 -1
  11. data/app/models/devise/mailer.rb +17 -11
  12. data/app/views/devise/confirmations/new.html.erb +1 -1
  13. data/app/views/devise/passwords/edit.html.erb +1 -1
  14. data/app/views/devise/passwords/new.html.erb +1 -1
  15. data/app/views/devise/registrations/edit.html.erb +2 -2
  16. data/app/views/devise/registrations/new.html.erb +2 -2
  17. data/app/views/devise/sessions/new.html.erb +2 -2
  18. data/app/views/devise/shared/_links.erb +5 -5
  19. data/app/views/devise/unlocks/new.html.erb +1 -1
  20. data/config/locales/en.yml +4 -9
  21. data/lib/devise.rb +83 -42
  22. data/lib/devise/controllers/helpers.rb +6 -18
  23. data/lib/devise/controllers/internal_helpers.rb +11 -12
  24. data/lib/devise/controllers/scoped_views.rb +2 -2
  25. data/lib/devise/controllers/url_helpers.rb +1 -1
  26. data/lib/devise/failure_app.rb +56 -16
  27. data/lib/devise/hooks/activatable.rb +18 -6
  28. data/lib/devise/hooks/rememberable.rb +36 -27
  29. data/lib/devise/hooks/timeoutable.rb +1 -1
  30. data/lib/devise/hooks/trackable.rb +4 -2
  31. data/lib/devise/mapping.rb +19 -14
  32. data/lib/devise/models.rb +12 -3
  33. data/lib/devise/models/authenticatable.rb +19 -95
  34. data/lib/devise/models/confirmable.rb +14 -20
  35. data/lib/devise/models/database_authenticatable.rb +99 -0
  36. data/lib/devise/models/lockable.rb +53 -39
  37. data/lib/devise/models/recoverable.rb +3 -3
  38. data/lib/devise/models/rememberable.rb +5 -10
  39. data/lib/devise/models/token_authenticatable.rb +18 -25
  40. data/lib/devise/models/validatable.rb +14 -9
  41. data/lib/devise/modules.rb +7 -8
  42. data/lib/devise/orm/active_record.rb +1 -1
  43. data/lib/devise/orm/data_mapper.rb +20 -7
  44. data/lib/devise/orm/mongoid.rb +40 -0
  45. data/lib/devise/rails.rb +26 -3
  46. data/lib/devise/rails/routes.rb +18 -16
  47. data/lib/devise/rails/warden_compat.rb +2 -2
  48. data/lib/devise/schema.rb +45 -18
  49. data/lib/devise/strategies/authenticatable.rb +92 -21
  50. data/lib/devise/strategies/base.rb +6 -3
  51. data/lib/devise/strategies/database_authenticatable.rb +20 -0
  52. data/lib/devise/strategies/rememberable.rb +10 -6
  53. data/lib/devise/strategies/token_authenticatable.rb +28 -19
  54. data/lib/devise/test_helpers.rb +5 -1
  55. data/lib/devise/version.rb +1 -1
  56. data/lib/generators/devise/devise_generator.rb +15 -5
  57. data/lib/generators/devise/templates/migration.rb +2 -2
  58. data/lib/generators/devise_install/templates/devise.rb +37 -16
  59. data/lib/generators/devise_views/devise_views_generator.rb +51 -4
  60. data/test/controllers/helpers_test.rb +16 -8
  61. data/test/controllers/internal_helpers_test.rb +6 -1
  62. data/test/controllers/url_helpers_test.rb +10 -10
  63. data/test/devise_test.rb +13 -17
  64. data/test/encryptors_test.rb +2 -0
  65. data/test/failure_app_test.rb +72 -23
  66. data/test/integration/confirmable_test.rb +4 -4
  67. data/test/integration/{authenticatable_test.rb → database_authenticatable_test.rb} +35 -17
  68. data/test/integration/http_authenticatable_test.rb +3 -3
  69. data/test/integration/lockable_test.rb +28 -8
  70. data/test/integration/recoverable_test.rb +3 -3
  71. data/test/integration/registerable_test.rb +6 -4
  72. data/test/integration/rememberable_test.rb +11 -4
  73. data/test/integration/timeoutable_test.rb +4 -4
  74. data/test/integration/token_authenticatable_test.rb +46 -10
  75. data/test/integration/trackable_test.rb +2 -2
  76. data/test/mailers/confirmation_instructions_test.rb +5 -5
  77. data/test/mailers/reset_password_instructions_test.rb +5 -5
  78. data/test/mailers/unlock_instructions_test.rb +5 -5
  79. data/test/mapping_test.rb +15 -14
  80. data/test/models/confirmable_test.rb +9 -32
  81. data/test/models/{authenticatable_test.rb → database_authenticatable_test.rb} +2 -34
  82. data/test/models/lockable_test.rb +48 -66
  83. data/test/models/recoverable_test.rb +8 -8
  84. data/test/models/rememberable_test.rb +6 -28
  85. data/test/models/timeoutable_test.rb +1 -1
  86. data/test/models/token_authenticatable_test.rb +1 -8
  87. data/test/models/trackable_test.rb +1 -1
  88. data/test/models/validatable_test.rb +2 -2
  89. data/test/models_test.rb +16 -2
  90. data/test/orm/active_record.rb +1 -22
  91. data/test/orm/data_mapper.rb +1 -0
  92. data/test/orm/mongoid.rb +10 -0
  93. data/test/rails_app/app/active_record/admin.rb +1 -5
  94. data/test/rails_app/app/controllers/application_controller.rb +2 -0
  95. data/test/rails_app/app/controllers/sessions_controller.rb +1 -1
  96. data/test/rails_app/app/data_mapper/admin.rb +13 -0
  97. data/test/rails_app/app/data_mapper/user.rb +24 -0
  98. data/test/rails_app/app/mongoid/admin.rb +15 -0
  99. data/test/rails_app/app/mongoid/user.rb +21 -0
  100. data/test/rails_app/config/application.rb +10 -5
  101. data/test/rails_app/config/boot.rb +5 -1
  102. data/test/rails_app/config/initializers/devise.rb +1 -1
  103. data/test/rails_app/config/routes.rb +4 -1
  104. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +27 -0
  105. data/test/rails_app/db/schema.rb +86 -0
  106. data/test/routes_test.rb +3 -3
  107. data/test/support/assertions.rb +2 -0
  108. data/test/support/helpers.rb +2 -0
  109. data/test/support/integration.rb +4 -7
  110. data/test/support/webrat/integrations/rails.rb +2 -1
  111. data/test/test_helper.rb +5 -2
  112. data/test/test_helpers_test.rb +4 -4
  113. metadata +36 -21
  114. data/lib/devise/models/http_authenticatable.rb +0 -19
  115. data/lib/devise/orm/mongo_mapper.rb +0 -49
  116. data/lib/devise/strategies/http_authenticatable.rb +0 -47
  117. data/test/models/http_authenticatable_test.rb +0 -19
  118. data/test/orm/mongo_mapper.rb +0 -12
  119. data/test/rails_app/app/mongo_mapper/admin.rb +0 -10
  120. data/test/rails_app/app/mongo_mapper/user.rb +0 -11
  121. data/test/rails_app/config/initializers/cookie_verification_secret.rb +0 -7
  122. data/test/rails_app/config/initializers/session_store.rb +0 -15
@@ -13,41 +13,41 @@ module Devise
13
13
  # Configuration:
14
14
  #
15
15
  # maximum_attempts: how many attempts should be accepted before blocking the user.
16
- # unlock_strategy: unlock the user account by :time, :email or :both.
16
+ # lock_strategy: lock the user account by :failed_attempts or :none.
17
+ # unlock_strategy: unlock the user account by :time, :email, :both or :none.
17
18
  # unlock_in: the time you want to lock the user after to lock happens. Only
18
19
  # available when unlock_strategy is :time or :both.
19
20
  #
20
21
  module Lockable
21
- extend ActiveSupport::Concern
22
+ extend ActiveSupport::Concern
22
23
  include Devise::Models::Activatable
23
24
 
25
+ delegate :lock_strategy_enabled?, :unlock_strategy_enabled?, :to => "self.class"
26
+
24
27
  # Lock an user setting it's locked_at to actual time.
25
- def lock
28
+ def lock_access!
26
29
  self.locked_at = Time.now
30
+
27
31
  if unlock_strategy_enabled?(:email)
28
32
  generate_unlock_token
29
33
  send_unlock_instructions
30
34
  end
31
- end
32
35
 
33
- # Lock an user also saving the record.
34
- def lock!
35
- lock
36
36
  save(:validate => false)
37
37
  end
38
38
 
39
39
  # Unlock an user by cleaning locket_at and failed_attempts.
40
- def unlock!
41
- if_locked do
40
+ def unlock_access!
41
+ if_access_locked do
42
42
  self.locked_at = nil
43
- self.failed_attempts = 0
44
- self.unlock_token = nil
43
+ self.failed_attempts = 0 if respond_to?(:failed_attempts=)
44
+ self.unlock_token = nil if respond_to?(:unlock_token=)
45
45
  save(:validate => false)
46
46
  end
47
47
  end
48
48
 
49
49
  # Verifies whether a user is locked or not.
50
- def locked?
50
+ def access_locked?
51
51
  locked_at && !lock_expired?
52
52
  end
53
53
 
@@ -57,49 +57,54 @@ module Devise
57
57
  end
58
58
 
59
59
  # Resend the unlock instructions if the user is locked.
60
- def resend_unlock!
61
- if_locked do
62
- generate_unlock_token unless unlock_token.present?
63
- save(:validate => false)
64
- send_unlock_instructions
65
- end
60
+ def resend_unlock_token
61
+ if_access_locked { send_unlock_instructions }
66
62
  end
67
63
 
68
64
  # Overwrites active? from Devise::Models::Activatable for locking purposes
69
65
  # by verifying whether an user is active to sign in or not based on locked?
70
66
  def active?
71
- super && !locked?
67
+ super && !access_locked?
72
68
  end
73
69
 
74
70
  # Overwrites invalid_message from Devise::Models::Authenticatable to define
75
71
  # the correct reason for blocking the sign in.
76
72
  def inactive_message
77
- if locked?
78
- :locked
79
- else
80
- super
81
- end
73
+ access_locked? ? :locked : super
82
74
  end
83
75
 
84
76
  # Overwrites valid_for_authentication? from Devise::Models::Authenticatable
85
77
  # for verifying whether an user is allowed to sign in or not. If the user
86
78
  # is locked, it should never be allowed.
87
- def valid_for_authentication?(attributes)
79
+ def valid_for_authentication?
80
+ return :locked if access_locked?
81
+ return super unless persisted?
82
+ return super unless lock_strategy_enabled?(:failed_attempts)
83
+
88
84
  if result = super
89
85
  self.failed_attempts = 0
90
86
  else
91
87
  self.failed_attempts += 1
92
- lock if failed_attempts > self.class.maximum_attempts
88
+
89
+ if attempts_exceeded?
90
+ lock_access!
91
+ return :locked
92
+ end
93
93
  end
94
+
94
95
  save(:validate => false) if changed?
95
96
  result
96
97
  end
97
98
 
98
99
  protected
99
100
 
101
+ def attempts_exceeded?
102
+ self.failed_attempts > self.class.maximum_attempts
103
+ end
104
+
100
105
  # Generates unlock token
101
106
  def generate_unlock_token
102
- self.unlock_token = Devise.friendly_token
107
+ self.unlock_token = self.class.unlock_token
103
108
  end
104
109
 
105
110
  # Tells if the lock is expired if :time unlock strategy is active
@@ -113,8 +118,8 @@ module Devise
113
118
 
114
119
  # Checks whether the record is locked or not, yielding to the block
115
120
  # if it's locked, otherwise adds an error to email.
116
- def if_locked
117
- if locked?
121
+ def if_access_locked
122
+ if access_locked?
118
123
  yield
119
124
  else
120
125
  self.errors.add(:email, :not_locked)
@@ -122,11 +127,6 @@ module Devise
122
127
  end
123
128
  end
124
129
 
125
- # Is the unlock enabled for the given unlock strategy?
126
- def unlock_strategy_enabled?(strategy)
127
- [:both, strategy].include?(self.class.unlock_strategy)
128
- end
129
-
130
130
  module ClassMethods
131
131
  # Attempt to find a user by it's email. If a record is found, send new
132
132
  # unlock instructions to it. If not user is found, returns a new user
@@ -134,7 +134,7 @@ module Devise
134
134
  # Options must contain the user email
135
135
  def send_unlock_instructions(attributes={})
136
136
  lockable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
137
- lockable.resend_unlock! unless lockable.new_record?
137
+ lockable.resend_unlock_token if lockable.persisted?
138
138
  lockable
139
139
  end
140
140
 
@@ -142,13 +142,27 @@ module Devise
142
142
  # If no user is found, returns a new user with an error.
143
143
  # If the user is not locked, creates an error for the user
144
144
  # Options must have the unlock_token
145
- def unlock!(attributes={})
146
- lockable = find_or_initialize_with_error_by(:unlock_token, attributes[:unlock_token])
147
- lockable.unlock! unless lockable.new_record?
145
+ def unlock_access_by_token(unlock_token)
146
+ lockable = find_or_initialize_with_error_by(:unlock_token, unlock_token)
147
+ lockable.unlock_access! if lockable.persisted?
148
148
  lockable
149
149
  end
150
150
 
151
- Devise::Models.config(self, :maximum_attempts, :unlock_strategy, :unlock_in)
151
+ # Is the unlock enabled for the given unlock strategy?
152
+ def unlock_strategy_enabled?(strategy)
153
+ [:both, strategy].include?(self.unlock_strategy)
154
+ end
155
+
156
+ # Is the lock enabled for the given lock strategy?
157
+ def lock_strategy_enabled?(strategy)
158
+ self.lock_strategy == strategy
159
+ end
160
+
161
+ def unlock_token
162
+ Devise.friendly_token
163
+ end
164
+
165
+ Devise::Models.config(self, :maximum_attempts, :lock_strategy, :unlock_strategy, :unlock_in)
152
166
  end
153
167
  end
154
168
  end
@@ -56,7 +56,7 @@ module Devise
56
56
  # Attributes must contain the user email
57
57
  def send_reset_password_instructions(attributes={})
58
58
  recoverable = find_or_initialize_with_error_by(:email, attributes[:email], :not_found)
59
- recoverable.send_reset_password_instructions unless recoverable.new_record?
59
+ recoverable.send_reset_password_instructions if recoverable.persisted?
60
60
  recoverable
61
61
  end
62
62
 
@@ -65,9 +65,9 @@ module Devise
65
65
  # try saving the record. If not user is found, returns a new user
66
66
  # containing an error in reset_password_token attribute.
67
67
  # Attributes must contain reset_password_token, password and confirmation
68
- def reset_password!(attributes={})
68
+ def reset_password_by_token(attributes={})
69
69
  recoverable = find_or_initialize_with_error_by(:reset_password_token, attributes[:reset_password_token])
70
- recoverable.reset_password!(attributes[:password], attributes[:password_confirmation]) unless recoverable.new_record?
70
+ recoverable.reset_password!(attributes[:password], attributes[:password_confirmation]) if recoverable.persisted?
71
71
  recoverable
72
72
  end
73
73
  end
@@ -54,11 +54,6 @@ module Devise
54
54
  end
55
55
  end
56
56
 
57
- # Checks whether the incoming token matches or not with the record token.
58
- def valid_remember_token?(token)
59
- remember_token && !remember_expired? && remember_token == token
60
- end
61
-
62
57
  # Remember token should be expired if expiration time not overpass now.
63
58
  def remember_expired?
64
59
  remember_expires_at <= Time.now.utc
@@ -72,14 +67,14 @@ module Devise
72
67
  module ClassMethods
73
68
  # Create the cookie key using the record id and remember_token
74
69
  def serialize_into_cookie(record)
75
- "#{record.id}::#{record.remember_token}"
70
+ [record.id, record.remember_token]
76
71
  end
77
72
 
78
73
  # Recreate the user based on the stored cookie
79
- def serialize_from_cookie(cookie)
80
- record_id, record_token = cookie.split('::')
81
- record = find(:first, :conditions => { :id => record_id }) if record_id
82
- record if record.try(:valid_remember_token?, record_token)
74
+ def serialize_from_cookie(id, remember_token)
75
+ conditions = { :id => id, :remember_token => remember_token }
76
+ record = find(:first, :conditions => conditions)
77
+ record if record && !record.remember_expired?
83
78
  end
84
79
 
85
80
  Devise::Models.config(self, :remember_for)
@@ -18,7 +18,8 @@ module Devise
18
18
  # User.find(1).valid_authentication_token?('rI1t6PKQ8yP7VetgwdybB') # returns true/false
19
19
  #
20
20
  module TokenAuthenticatable
21
- extend ActiveSupport::Concern
21
+ extend ActiveSupport::Concern
22
+ include Devise::Models::Authenticatable
22
23
 
23
24
  included do
24
25
  before_save :ensure_authentication_token
@@ -45,43 +46,35 @@ module Devise
45
46
  self.reset_authentication_token! if self.authentication_token.blank?
46
47
  end
47
48
 
48
- # Verifies whether an +incoming_authentication_token+ (i.e. from single access URL)
49
- # is the user authentication token.
50
- def valid_authentication_token?(incoming_auth_token)
51
- incoming_auth_token.present? && incoming_auth_token == self.authentication_token
52
- end
53
-
54
49
  module ClassMethods
55
50
  ::Devise::Models.config(self, :token_authentication_key)
56
51
 
57
52
  # Authenticate a user based on authentication token.
58
53
  def authenticate_with_token(attributes)
59
54
  token = attributes[self.token_authentication_key]
60
- resource = self.find_for_token_authentication(token)
61
- resource if resource.try(:valid_authentication_token?, token)
55
+ self.find_for_token_authentication(token)
62
56
  end
63
57
 
64
58
  def authentication_token
65
59
  ::Devise.friendly_token
66
60
  end
67
61
 
68
- protected
69
-
70
- # Find first record based on conditions given (ie by the sign in form).
71
- # Overwrite to add customized conditions, create a join, or maybe use a
72
- # namedscope to filter records while authenticating.
73
- #
74
- # == Example:
75
- #
76
- # def self.find_for_token_authentication(token, conditions = {})
77
- # conditions = {:active => true}
78
- # self.find_by_authentication_token(token, :conditions => conditions)
79
- # end
80
- #
81
- def find_for_token_authentication(token)
82
- self.find(:first, :conditions => { :authentication_token => token})
83
- end
62
+ protected
84
63
 
64
+ # Find first record based on conditions given (ie by the sign in form).
65
+ # Overwrite to add customized conditions, create a join, or maybe use a
66
+ # namedscope to filter records while authenticating.
67
+ #
68
+ # == Example:
69
+ #
70
+ # def self.find_for_token_authentication(token, conditions = {})
71
+ # conditions = {:active => true}
72
+ # super
73
+ # end
74
+ #
75
+ def find_for_token_authentication(token)
76
+ self.find(:first, :conditions => { :authentication_token => token})
77
+ end
85
78
  end
86
79
  end
87
80
  end
@@ -11,17 +11,18 @@ module Devise
11
11
  :validates_confirmation_of, :validates_length_of ].freeze
12
12
 
13
13
  def self.included(base)
14
+ base.extend ClassMethods
14
15
  assert_validations_api!(base)
15
16
 
16
17
  base.class_eval do
17
18
  validates_presence_of :email
18
19
  validates_uniqueness_of :email, :scope => authentication_keys[1..-1], :allow_blank => true
19
- validates_format_of :email, :with => EMAIL_REGEX, :allow_blank => true
20
+ validates_format_of :email, :with => email_regexp, :allow_blank => true
20
21
 
21
22
  with_options :if => :password_required? do |v|
22
23
  v.validates_presence_of :password
23
24
  v.validates_confirmation_of :password
24
- v.validates_length_of :password, :within => 6..20, :allow_blank => true
25
+ v.validates_length_of :password, :within => password_length, :allow_blank => true
25
26
  end
26
27
  end
27
28
  end
@@ -35,14 +36,18 @@ module Devise
35
36
  end
36
37
  end
37
38
 
38
- protected
39
+ protected
39
40
 
40
- # Checks whether a password is needed or not. For validations only.
41
- # Passwords are always required if it's a new record, or if the password
42
- # or confirmation are being set somewhere.
43
- def password_required?
44
- new_record? || !password.nil? || !password_confirmation.nil?
45
- end
41
+ # Checks whether a password is needed or not. For validations only.
42
+ # Passwords are always required if it's a new record, or if the password
43
+ # or confirmation are being set somewhere.
44
+ def password_required?
45
+ !persisted? || !password.nil? || !password_confirmation.nil?
46
+ end
47
+
48
+ module ClassMethods
49
+ Devise::Models.config(self, :email_regexp, :password_length)
50
+ end
46
51
  end
47
52
  end
48
53
  end
@@ -2,10 +2,9 @@ require 'active_support/core_ext/object/with_options'
2
2
 
3
3
  Devise.with_options :model => true do |d|
4
4
  # Strategies first
5
- d.with_options :strategy => true do |s|
6
- s.add_module :authenticatable, :controller => :sessions, :flash => :invalid, :route => :session
7
- s.add_module :http_authenticatable
8
- s.add_module :token_authenticatable, :controller => :sessions, :flash => :invalid_token, :route => :session
5
+ d.with_options :strategy => true do |s|
6
+ s.add_module :database_authenticatable, :controller => :sessions, :route => :session
7
+ s.add_module :token_authenticatable, :controller => :sessions, :route => :session
9
8
  s.add_module :rememberable
10
9
  end
11
10
 
@@ -15,10 +14,10 @@ Devise.with_options :model => true do |d|
15
14
  d.add_module :validatable
16
15
 
17
16
  # The ones which can sign out after
18
- d.add_module :activatable, :flash => :inactive
19
- d.add_module :confirmable, :controller => :confirmations, :flash => :unconfirmed, :route => :confirmation
20
- d.add_module :lockable, :controller => :unlocks, :flash => :locked, :route => :unlock
21
- d.add_module :timeoutable, :flash => :timeout
17
+ d.add_module :activatable
18
+ d.add_module :confirmable, :controller => :confirmations, :route => :confirmation
19
+ d.add_module :lockable, :controller => :unlocks, :route => :unlock
20
+ d.add_module :timeoutable
22
21
 
23
22
  # Stats for last, so we make sure the user is really signed in
24
23
  d.add_module :trackable
@@ -3,7 +3,7 @@ module Devise
3
3
  # This module contains some helpers and handle schema (migrations):
4
4
  #
5
5
  # create_table :accounts do |t|
6
- # t.authenticatable
6
+ # t.database_authenticatable
7
7
  # t.confirmable
8
8
  # t.recoverable
9
9
  # t.rememberable
@@ -24,9 +24,10 @@ module Devise
24
24
  def apply_schema(name, type, options={})
25
25
  SCHEMA_OPTIONS.each do |old_key, new_key|
26
26
  next unless options.key?(old_key)
27
- options[new_key] = !options.delete(old_key)
27
+ options[new_key] = options.delete(old_key)
28
28
  end
29
29
 
30
+ options.delete(:default) if options[:default].nil?
30
31
  property name, type, options
31
32
  end
32
33
  end
@@ -37,18 +38,22 @@ module Devise
37
38
  module ClassMethods
38
39
  # Hooks for confirmable
39
40
  def before_create(*args)
40
- wrap_hook(:before, *args)
41
+ wrap_hook(:before, :create, *args)
41
42
  end
42
43
 
43
44
  def after_create(*args)
44
- wrap_hook(:after, *args)
45
+ wrap_hook(:after, :create, *args)
46
+ end
47
+
48
+ def before_save(*args)
49
+ wrap_hook(:before, :save, *args)
45
50
  end
46
51
 
47
- def wrap_hook(action, *args)
52
+ def wrap_hook(action, method, *args)
48
53
  options = args.extract_options!
49
54
 
50
55
  args.each do |callback|
51
- send action, :create, callback
56
+ send action, method, callback
52
57
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
53
58
  def #{callback}
54
59
  super if #{options[:if] || true}
@@ -67,6 +72,10 @@ module Devise
67
72
  end
68
73
  end
69
74
  end
75
+
76
+ def changed?
77
+ dirty?
78
+ end
70
79
 
71
80
  def save(options=nil)
72
81
  if options.is_a?(Hash) && options[:validate] == false
@@ -75,12 +84,16 @@ module Devise
75
84
  super()
76
85
  end
77
86
  end
87
+
88
+ def update_attributes(*args)
89
+ update(*args)
90
+ end
78
91
  end
79
92
  end
80
93
  end
81
94
  end
82
95
 
83
96
  DataMapper::Model.class_eval do
84
- extend Devise::ORM::DataMapper::Hook
85
97
  include Devise::Models
86
- end
98
+ include Devise::Orm::DataMapper::Hook
99
+ end