Question about Devise + Soft Deletion + scoped resource

615 views
Skip to first unread message

Andy Lin

unread,
Apr 12, 2013, 3:51:34 AM4/12/13
to plataforma...@googlegroups.com

Hello, I hope I am posting to the right place for questions as this is what the github page seems to suggest. I have asked this question on stackoverflow and am reasking here since no one has responded, and not many people have even looked at it. 

Anyway, I am using Devise as authentication for a rails 3.2 app. My user model is called User, and I've been trying to implement a soft delete. I am trying to do this by using acts_as_paranoid, which does much of the work for me. Things work as expected (others can no longer see the "deleted" user), except that I want the deactivated user to still be able to log in and see a "deactivated" screen, and give them the chance to reactivate their account.

The problem is that Devise (Warden?) is no longer able to find the deleted user. Acts_as_paranoid lets you access the soft deleted records if you use the scope "with_deleted" (as in User.with_deleted.find etc.). So I am able to get part of the way there with:

def self.find_first_by_auth_conditions(warden_conditions)
  conditions = warden_conditions.dup
  where(conditions).with_deleted.first
end

I put this into my user model, and so now when I input the log in information, I'll get the flash message that I have successfully logged in, and it'll touch the "updated_at" column in the user model and increment the sign_in_count, etc. However, it doesn't really authenticate in the sense that the authenticated method returns false and the current_user helper method returns nil. When I check the session dump, i see that I have a flash notice, but there is, unlike if a regular non-soft-deleted user signs in, any information about the user. What is weird is that if I use the rails console and try to do this manually (app.post('/signin', {"user"=>{"email"=>"us...@user.com", "password"=>"useruser"}}), and then I did: app.controller.current_user , it returns the user. So it works in the rails console but not actually.

Does anyone have any ideas about this? Can I override the current_user method somehow so that it queries the User model with the with_deleted scope? (relatedly, is it possible to put a scoped model ("User.scoped") into a symboled resource?)) Do I have to do something with warden, such as added conditions like I did with the find_first_by_auth_conditions method? My guess is that Warden isn't really authenticating, but the session controller is, but I"m not sure how to fix this; do i have to write a separately Warden strategy? Any help is appreciated!

also, after I do get it working, I would like to automatically send all soft deleted users to a "deactivated" page where their only options are to permanently delete or reactivate. Is there some way to do this with routing via the "authenticated :user do {} end", or do i have to put a before_filter in the application_controller and check for the user at every request?

Thank you!

Andy

Lucas Mazza

unread,
Apr 15, 2013, 9:40:18 PM4/15/13
to plataforma...@googlegroups.com
One other place you might need to change is the "serialize_from_session" method, that is the one used by Warden when the User object is retrieved from the session. After that I believe that most of your Devise related problems might be gone, otherwise just search for database interactions in the Devise source (lib/devise/models/*.rb) and see what you might need to override to get it working. 

Related to a "deactivated" page, I guess it will be hard to avoid the before_filter approach, since you probably need to protect several actions/routes from deactivated users. 

Hope that this might help you get going with your app!


Andy

--
 
---
You received this message because you are subscribed to the Google Groups "Devise" group.
To unsubscribe from this group and stop receiving emails from it, send an email to plataformatec-de...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Andy Lin

unread,
Apr 17, 2013, 9:56:37 PM4/17/13
to plataforma...@googlegroups.com
Thanks for this tip! I was able to get it working by putting this into the User model:

  protected 

  def self.serialize_from_session(key, salt)
    record = with_deleted.find(key).first
    record if record && record.authenticatable_salt == salt
  end

Uncertain if this is the best way to do it, but it works and that's good enough for me. 

I spent a bit of time trying to write a different strategy and also by trying to override the gem's module using an initializer and module_eval / class_eval, but I kept getting all errors related to uninitialized constant / name error, even though I thought I was naming everything correctly.  Maybe I will try to write a strategy in the future as an exercise and see if I can figure out the errors, but for now, I am just relieved to have this working! It took me quite awhile to get it, and thanks again for helping me get to the bottom of it.

Andy
To unsubscribe from this group and stop receiving emails from it, send an email to plataformatec-devise+unsub...@googlegroups.com.

Andy Lin

unread,
Apr 17, 2013, 10:18:52 PM4/17/13
to plataforma...@googlegroups.com
Also, with regards to redirecting the soft-deleted users, as you mentioned, I went ahead and put a before_filter in my application controller as follows:

  before_filter :catch_deactivated, except: :deactivated

  private
    def catch_deactivated
      if current_user.present?
        redirect_to deactivated_user_path(current_user) if current_user.deleted_at? 
      end
    end


I guess I can't htink of any other way to do this since one way or another, the application does have to check it at every request. (Maybe I was hoping this can be sorted at the same time as "authenticate_user!"... If I get bored, maybe I'll look into that helper method..)

Hopefully this helps someone. If not, glad I learned something.
Reply all
Reply to author
Forward
0 new messages