From bb2725c6e028f102c729bac053783ce9db03e789 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Fri, 31 Mar 2023 11:41:23 -0300 Subject: [PATCH] Update dirty tracking to support Mongoid 8.0+ It appears Mongoid 8.0+ slightly [changed dirty tracking] behavior to more closely match Active Model/Record, however they haven't yet introduced the [new methods] that match the latest API, that seems to be coming on Mongoid 8.1 only. The changes here try to accommodate for that by determining which "attribute_changed?" method to call depending on whether the "*_previously_*" version exists. Newer versions of AR (5.1+) will continue to use the new API / methods, whereas previous versions and Mongoid 8.0+ will use these tweaked versions. No behavior should change for AR, but it will hopefully support Mongoid 8.0+ now. [changed dirty tracking] https://github.com/mongodb/mongoid/pull/5092 [new methods] https://github.com/mongodb/mongoid/pull/5440 --- CHANGELOG.md | 2 +- gemfiles/Gemfile-rails-main | 3 ++- lib/devise/orm.rb | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 494188853..0600227c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * enhancements * Removed deprecations warning output for `Devise::Models::Authenticatable::BLACKLIST_FOR_SERIALIZATION` (@soartec-lab) + * Reenable Mongoid test suite across all Rails 6+ versions, to ensure we continue supporting it. Changes to dirty tracking to support Mongoid 8.0+. [#5568](https://github.com/heartcombo/devise/pull/5568) * bug fixes * Respect locale set by controller in failure app. Devise will carry over the current I18n.locale option when triggering authentication, and will wrap the failure app call with it. [#5567](https://github.com/heartcombo/devise/pull/5567) @@ -26,7 +27,6 @@ * Allow resource class scopes to override the global configuration for `sign_in_after_reset_password` behaviour. [#5429](https://github.com/heartcombo/devise/pull/5429) [@mattr](https://github.com/mattr) * Refactor conditional dirty tracking logic to a centralized module to simplify usage throughout the codebase. [#5575](https://github.com/heartcombo/devise/pull/5575) * Improve support for Devise in apps with Active Record and Mongoid ORMs loaded, so it does not incorrectly uses new Active Record dirty tracking APIs with a Mongoid Devise model. [#5576](https://github.com/heartcombo/devise/pull/5576) - * Reenable Mongoid test suite across all Rails 5+ versions, to ensure we continue supporting it. (Note: testing support with Mongoid up to 7.x, not 8 yet.) [#5568](https://github.com/heartcombo/devise/pull/5568) * bug fixes * Failure app will respond with configured `redirect_status` instead of `error_status` if the recall app returns a redirect status (300..399) [#5573](https://github.com/heartcombo/devise/pull/5573) diff --git a/gemfiles/Gemfile-rails-main b/gemfiles/Gemfile-rails-main index da31739d1..27e3a394a 100644 --- a/gemfiles/Gemfile-rails-main +++ b/gemfiles/Gemfile-rails-main @@ -25,5 +25,6 @@ platforms :ruby do end group :mongoid do - gem "mongoid", "~> 7.5" + # gem "mongoid", "~> 8.1" + gem "mongoid", github: "mongodb/mongoid", branch: "8.1-stable" end diff --git a/lib/devise/orm.rb b/lib/devise/orm.rb index 3e9852cd3..4c3cd6f49 100644 --- a/lib/devise/orm.rb +++ b/lib/devise/orm.rb @@ -5,10 +5,14 @@ def self.active_record?(model) end def self.included(model) - model.include DirtyTrackingMethods + if Devise::Orm.active_record?(model) + model.include DirtyTrackingActiveRecordMethods + else + model.include DirtyTrackingMongoidMethods + end end - module DirtyTrackingMethods + module DirtyTrackingActiveRecordMethods def devise_email_before_last_save email_before_last_save end @@ -33,5 +37,31 @@ def devise_respond_to_and_will_save_change_to_attribute?(attribute) respond_to?("will_save_change_to_#{attribute}?") && send("will_save_change_to_#{attribute}?") end end + + module DirtyTrackingMongoidMethods + def devise_email_before_last_save + respond_to?(:email_previously_was) ? email_previously_was : email_was + end + + def devise_email_in_database + email_was + end + + def devise_saved_change_to_email? + respond_to?(:email_previously_changed?) ? email_previously_changed? : email_changed? + end + + def devise_saved_change_to_encrypted_password? + respond_to?(:encrypted_password_previously_changed?) ? encrypted_password_previously_changed? : encrypted_password_changed? + end + + def devise_will_save_change_to_email? + email_changed? + end + + def devise_respond_to_and_will_save_change_to_attribute?(attribute) + respond_to?("#{attribute}_changed?") && send("#{attribute}_changed?") + end + end end end