devise: undefined method `will_save_change_to_email?' for User

Hi, I have problems with:

  • Devise 4.3
  • Rails 5.1
  • Mongoid 6.1
NoMethodError (undefined method `will_save_change_to_email?' for #<User:0x007f80b1778ec0>):
  
activesupport (5.1.1) lib/active_support/callbacks.rb:413:in `block in make_lambda'
activesupport (5.1.1) lib/active_support/callbacks.rb:177:in `block (2 levels) in halting_and_conditional'
activesupport (5.1.1) lib/active_support/callbacks.rb:177:in `each'
activesupport (5.1.1) lib/active_support/callbacks.rb:177:in `all?'
activesupport (5.1.1) lib/active_support/callbacks.rb:177:in `block in halting_and_conditional'
activesupport (5.1.1) lib/active_support/callbacks.rb:507:in `block in invoke_before'
activesupport (5.1.1) lib/active_support/callbacks.rb:507:in `each'
activesupport (5.1.1) lib/active_support/callbacks.rb:507:in `invoke_before'
activesupport (5.1.1) lib/active_support/callbacks.rb:130:in `run_callbacks'
mongoid (6.1.0) lib/mongoid/interceptable.rb:138:in `run_callbacks'
activesupport (5.1.1) lib/active_support/callbacks.rb:825:in `_run_validate_callbacks'
activemodel (5.1.1) lib/active_model/validations.rb:405:in `run_validations!'
activemodel (5.1.1) lib/active_model/validations/callbacks.rb:110:in `block in run_validations!'
activesupport (5.1.1) lib/active_support/callbacks.rb:131:in `run_callbacks'
mongoid (6.1.0) lib/mongoid/interceptable.rb:138:in `run_callbacks'
activesupport (5.1.1) lib/active_support/callbacks.rb:825:in `_run_validation_callbacks'
activemodel (5.1.1) lib/active_model/validations/callbacks.rb:110:in `run_validations!'
activemodel (5.1.1) lib/active_model/validations.rb:335:in `valid?'
mongoid (6.1.0) lib/mongoid/validatable.rb:97:in `valid?'
activemodel (5.1.1) lib/active_model/validations.rb:372:in `invalid?'
mongoid (6.1.0) lib/mongoid/persistable/creatable.rb:115:in `prepare_insert'
mongoid (6.1.0) lib/mongoid/persistable/creatable.rb:23:in `insert'
mongoid (6.1.0) lib/mongoid/persistable/savable.rb:23:in `save'
/Volumes/FdData/Users/mToribio/.rvm/gems/ruby-2.4.1/bundler/gems/devise_token_auth-73d82dbd0982/app/controllers/devise_token_auth/registrations_controller.rb:42:in `create'
actionpack (5.1.1) lib/action_controller/metal/basic_implicit_render.rb:4:in `send_action'
actionpack (5.1.1) lib/abstract_controller/base.rb:186:in `process_action'
actionpack (5.1.1) lib/action_controller/metal/rendering.rb:30:in `process_action'
actionpack (5.1.1) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
activesupport (5.1.1) lib/active_support/callbacks.rb:131:in `run_callbacks'
actionpack (5.1.1) lib/abstract_controller/callbacks.rb:19:in `process_action'
actionpack (5.1.1) lib/action_controller/metal/rescue.rb:20:in `process_action'
actionpack (5.1.1) lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
activesupport (5.1.1) lib/active_support/notifications.rb:166:in `block in instrument'
activesupport (5.1.1) lib/active_support/notifications/instrumenter.rb:21:in `instrument'
activesupport (5.1.1) lib/active_support/notifications.rb:166:in `instrument'
actionpack (5.1.1) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
actionpack (5.1.1) lib/action_controller/metal/params_wrapper.rb:252:in `process_action'
actionpack (5.1.1) lib/abstract_controller/base.rb:124:in `process'
actionview (5.1.1) lib/action_view/rendering.rb:30:in `process'
actionpack (5.1.1) lib/action_controller/metal.rb:189:in `dispatch'
actionpack (5.1.1) lib/action_controller/metal.rb:253:in `dispatch'
actionpack (5.1.1) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
actionpack (5.1.1) lib/action_dispatch/routing/route_set.rb:31:in `serve'
actionpack (5.1.1) lib/action_dispatch/routing/mapper.rb:16:in `block in <class:Constraints>'
actionpack (5.1.1) lib/action_dispatch/routing/mapper.rb:46:in `serve'
actionpack (5.1.1) lib/action_dispatch/journey/router.rb:46:in `block in serve'
actionpack (5.1.1) lib/action_dispatch/journey/router.rb:33:in `each'
actionpack (5.1.1) lib/action_dispatch/journey/router.rb:33:in `serve'
actionpack (5.1.1) lib/action_dispatch/routing/route_set.rb:832:in `call'
warden (1.2.7) lib/warden/manager.rb:36:in `block in call'
warden (1.2.7) lib/warden/manager.rb:35:in `catch'
warden (1.2.7) lib/warden/manager.rb:35:in `call'
rack (2.0.3) lib/rack/etag.rb:25:in `call'
rack (2.0.3) lib/rack/conditional_get.rb:38:in `call'
rack (2.0.3) lib/rack/head.rb:12:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/callbacks.rb:26:in `block in call'
activesupport (5.1.1) lib/active_support/callbacks.rb:97:in `run_callbacks'
actionpack (5.1.1) lib/action_dispatch/middleware/callbacks.rb:24:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/executor.rb:12:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/debug_exceptions.rb:59:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
railties (5.1.1) lib/rails/rack/logger.rb:36:in `call_app'
railties (5.1.1) lib/rails/rack/logger.rb:24:in `block in call'
activesupport (5.1.1) lib/active_support/tagged_logging.rb:69:in `block in tagged'
activesupport (5.1.1) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (5.1.1) lib/active_support/tagged_logging.rb:69:in `tagged'
railties (5.1.1) lib/rails/rack/logger.rb:24:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/remote_ip.rb:79:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/request_id.rb:25:in `call'
rack (2.0.3) lib/rack/runtime.rb:22:in `call'
activesupport (5.1.1) lib/active_support/cache/strategy/local_cache_middleware.rb:27:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/executor.rb:12:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/static.rb:125:in `call'
rack (2.0.3) lib/rack/sendfile.rb:111:in `call'
rack-cors (0.4.1) lib/rack/cors.rb:81:in `call'
railties (5.1.1) lib/rails/engine.rb:522:in `call'
puma (3.8.2) lib/puma/configuration.rb:224:in `call'
puma (3.8.2) lib/puma/server.rb:600:in `handle_request'
puma (3.8.2) lib/puma/server.rb:435:in `process_client'
puma (3.8.2) lib/puma/server.rb:299:in `block in run'
puma (3.8.2) lib/puma/thread_pool.rb:120:in `block in spawn_thread'

In rails 5.0 thats works good. I have been investigating a little more and I not found where is defined will_save_change_to_email?. I think thats could be the problem… For now, I will use Rails 5.0 but I would like use Rails 5.1.

Thanks in advance.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 3
  • Comments: 31 (10 by maintainers)

Commits related to this issue

Most upvoted comments

So it turns out that the model does not have an email attribute, and both email_required? and email_changed? had been defined inside the model to negate the validation in previous versions.

The project is one I’ve inherited and had the pleasure of taking from Rails 3 all the way up to 5.1, while switching from MySQL to Postgresql. It’s been, interesting…

TL;DR:

def will_save_change_to_email?
  false
end

works fine for me!

create a function in model file

def will_save_change_to_email? false end

DEVICE GEM IS WORKING FINE NO ISSUE AT ALL

Here is my following setup

Rails 5.2.6 ruby 2.7.3p183 (2021-04-05 revision 6847ee089d) [x86_64-linux] mongoid (7.0.13) devise (4.8.0) devise-encryptable (0.2.0)

In file “config/initializers/devise.rb”

require 'devise/orm/mongoid'

Problem

Device thinks you are using ActiveRecord even though you have created your rails application with the option --skip-active-record.

Why

You have a gem that is not compatible with mongoid and is using ActiveRecord monkey patching.

How

When device try to detect if you are using ActiveRecord be using the code below

defined?(ActiveRecord) && ActiveRecord.gem_version >= Gem::Version.new("5.1.x")

it comes up false positive.

Solution

Enter rails console and type in ActiveRecord and you should see error message:

NameError: uninitialized constant ActiveRecord
from (pry):13:in `<main>'

If you don’t then start removing gems until you see that error message.

For me it was the following gems that gave me grief:

  • crono
  • delayed_job_web
  • database_cleaner

I replaced “cromo” with “whenever”, “database_cleaner” with “database_cleaner-mongoid”

setting this 3 aliases “solved” the problem for me for now:

alias will_save_change_to_email? email_changed? alias email_in_database email_was alias email_before_last_save email_before_destroy_was

@chrisokamoto Unfortunately, I haven’t been able to dig deep into this yet. I’ll try to do it soon.

I am still face problem with this… I am using

  • rails 5.1.7
  • devise 4.6.2
  • activerecord 5.1.7
  • mongoid 6.4.4

I need both mongoid and activerecord on my system… the User class uses mongoid and has a field called email. Everything was working perfectly on rails 5.0 but since I updated Rails to 5.1.7 I get this message undefined method will_save_change_to_email?. I tried doing what it was suggested here on this thread, creating a method called will_save_change_to_email? on User.rb. but the expected behaviour is still not right. For example, when the user changes his email, Devise is not sending the email for the user to confirm his email again. Instead I just see a notice message saying that my data was updated, which means that I see the registrations.updated message instead of registrations.update_needs_confirmation message.

Any updates on this?

If you are using Rails 5.x with MongoID and NOT active record then you must comment out “require ‘active_storage/engine’” in the application.rb.

Active storage uses Active record.

Example

require_relative 'boot'

require 'rails'
# Pick the frameworks you want:
require 'active_model/railtie'
require 'active_job/railtie'
# require 'active_storage/engine'
require 'action_controller/railtie'
require 'action_mailer/railtie'
require 'action_view/railtie'
require 'action_cable/engine'
require 'sprockets/railtie'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module ReadSharedBooks
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.

    # Don't generate system test files.
    config.generators.system_tests = nil
  end
end

I ran into this as well, from a clean new rails application.

STR:

1.) rails new auth_test 2.) add and configure mongoid 3.) add and configure devise 4.) generate new User model using devise generator (generates a mongoid model) 5.) can’t sign up (undefined method 'will_save_change_to_email?' for User)

You can fix this problem by not including ActiveRecord: rails new auth_test -O

I’ve run into this as well.

The problem appears to be that devise only makes a global check for Devise.activerecord51? without consulting which ORM is actually storing the User model. In our case the User model is backed by Mongoid 6.4.1, not ActiveRecord. So devise is trying to call AR methods on a mongoid model which doesn’t support them.