diff --git a/lib/devise/models/confirmable.rb b/lib/devise/models/confirmable.rb index 6ce22c30f..e4ae57cdc 100644 --- a/lib/devise/models/confirmable.rb +++ b/lib/devise/models/confirmable.rb @@ -73,12 +73,16 @@ def self.required_fields(klass) required_methods end - # Confirm a user by setting it's confirmed_at to actual time. If the user - # is already confirmed, add an error to email field. If the user is invalid - # add errors + # Confirm a user by setting its confirmed_at to the current time. If the user + # is already confirmed, add an error to email field. + # + # Supported options: + # * `:ensure_valid` - When true, validations are run when saving the record (otherwise, validations are only run + # on reconfirmation, to ensure e-mail uniqueness). + # * `:ignore_period` - When true, skips checking whether the confirmation period is expired. def confirm(args = {}) pending_any_confirmation do - if confirmation_period_expired? + if !args[:ignore_period] && confirmation_period_expired? self.errors.add(:email, :confirmation_period_expired, period: Devise::TimeInflector.time_ago_in_words(self.class.confirm_within.ago)) return false diff --git a/test/models/confirmable_test.rb b/test/models/confirmable_test.rb index 31a955e72..b4b4f4983 100644 --- a/test/models/confirmable_test.rb +++ b/test/models/confirmable_test.rb @@ -387,6 +387,18 @@ def confirm_user_by_token_with_confirmation_sent_at(confirmation_sent_at) admin.stubs(:valid?).returns(false) assert_not admin.confirm(ensure_valid: true) end + + test 'should ignore the confirmation period when ignore_period is true' do + swap Devise, confirm_within: 3.days do + user = Timecop.freeze(4.days.ago) do + create_user + end + assert_not user.confirm + assert_not user.confirmed? + assert user.confirm(ignore_period: true) + assert user.confirmed? + end + end end class ReconfirmableTest < ActiveSupport::TestCase