devise icon indicating copy to clipboard operation
devise copied to clipboard

Lockable module uses ActiveRecord-specific code (increment_counters), breaks compatibility with other ORMs

Open tbelliard opened this issue 5 years ago • 4 comments

Environment

  • Ruby any
  • Rails any
  • Devise 4.6.0+

Current behavior

Following issue #4981 resolved by PR https://github.com/heartcombo/devise/pull/4996, commit https://github.com/heartcombo/devise/commit/62703943bef75aba09ec3e346aba4c9159300ecd introduced a call to an ActiveRecord-specific method (increment_counters). This call breaks compatibility with alternative ORMs like Sequel that rely on the interface provided by ActiveModel.

Expected behavior

Ideally Devise should remain as ORM-agnostic as possible and rely when possible on ActiveModel methods to interact with model classes. In this case that would probably mean having a (semi-)manual SQL call to get something equivalent to what is implemented in active record : failed_attempts = COALESCE(failed_attempts, 0) + 1 (see https://github.com/rails/rails/blob/32cfb82922bfc905b14d7d025287dac0b85b1668/activerecord/lib/active_record/counter_cache.rb#L63)

Honestly I am not totally sure whether there is a clean generic solution here to reach the desired result... even a semi-manual SQL call needs to rely to fairly low-level features of the ORM. If you already maintain some ORM-specific code in devise then I guess the best course of action might be to have alternative calls depending on whether the model is a ActiveRecord or Sequel or whatever else instance.

As a workaround for now I will implement a sequel-specific increment_counter method in my user model.

tbelliard avatar Feb 03 '20 08:02 tbelliard

Facing this issue too with the Nobrainer ORM.

zedtux avatar Oct 09 '20 13:10 zedtux

Looks like this was never caught because of the mongo ID support/tests not being there. That's something I plan to bring back, in which case I'll look into how we can change that update to be more agnostic.

Devise always aimed to be somewhat ORM agnostic, one of the reasons it uses orm_adapter: https://github.com/heartcombo/devise/blob/45b831c4ea5a35914037bd27fe88b76d7b3683a4/devise.gemspec#L23

It looks like that's not been updated in a while though, and it doesn't seem to support either of the two ORMs you mentioned above, so I'm not sure how much we'll be able to rely on it going forward... we'll see.

carlosantoniodasilva avatar Oct 09 '20 13:10 carlosantoniodasilva

Actually, I just realized there are adapters for Sequel and Nobrainer available as separate gems: https://rubygems.org/gems/orm_adapter-sequel https://rubygems.org/gems/orm_adapter-nobrainer

So maybe it's a matter of making sure orm_adapter supports some sort of "increment counter" feature that each of those can implement, and Devise can use in a more agnostic way? 🤔

carlosantoniodasilva avatar Oct 09 '20 13:10 carlosantoniodasilva

I wasn't able to figure out how to get this to work with Dynamoid either: https://github.com/Dynamoid/Dynamoid

brian-tanabe avatar Dec 23 '21 01:12 brian-tanabe