Devise: Convert an existing guest user to a registered user

这一生的挚爱 提交于 2019-12-23 19:33:31

问题


I'm logging every new user automatically into the site by creating a guest user as described here:

https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user

This allows every user to use some basic stuff on my site, e.g. creating comments.

Now, when the user decides to register, I want to convert the guest user into a registered user.

I tried to implement my own User.new_with_session method like this:

def self.new_with_session(params, session)
  user = User.find(session[:guest_user_id])

  user.name                  = params[:name]
  user.email                 = params[:email]
  user.password              = params[:password]
  user.password_confirmation = params[:password_confirmation]
  user.created_at            = nil
  user.updated_at            = nil
  user.confirmed_at          = nil
  user.guest                 = false

  user
rescue ActiveRecord::RecordNotFound
  super
end

But this doesn't work. Somehow, when submitting the form, devise somehow seems to detect that the user already exists in the DB, and so doesn't even try to do validations on it, etc., but simply exits the sign up process (because it's thinking the user is already signed in) and forwards to some other page, which results in a "You need to sign in or sign up before continuing." flash message.

As far as I can tell, this happens somewhere before Devise::RegistrationsController#create is even called.

So here's my question: is there a way to tell Devise not to think a user is logged in simply because the user already exists in the DB (although I don't have an idea how Devise knows about the user after submitting the registration form)?

Update

I could track the problem down a bit further. Whenever self.new_with_session returns a persisted record, the registration process is cancelled, as described above. When returning a new object, the registration continues. But I can't figure out where this is checked upon...!?


回答1:


For the moment, I stick with the following solution.

Instead of trying to convert the guest user into a registered one during the registration process, I let Devise do its magic and then after the registration completes, using an after hook, I immediately remove the newly registered user, then I convert the guest user to a registered one, assign the attributes provided through the user form to the former guest and sign it in.

class RegistrationsController < Devise::RegistrationsController
  after_filter :consolidate_registered_user_with_guest, only: :create,
                                                        if: -> { @user.valid? }

  def consolidate_registered_user_with_guest
    @current_user.annex_and_destroy!(@user)
    sign_in @current_user
  end
end

Then in User.rb:

def annex_and_destroy!(other)
  transaction do
    skip_confirmation_notification!

    other.delete
    other.attributes.except("id").each do |attribute, value|
      update_column attribute, value
    end

    self.save!
  end

  self
end

By using update_column I make sure that no before/after hooks are triggered, otherwise unpredictable things would happen, e.g. the confirmation mail would be re-sent (when setting the confirmation token), etc.

Keep in mind that any related records are not transferred from the created @user object to the existing @current_user automatically, so if you create any related objects (e.g. in an after hook), you have to manually move them, which is again a quite difficult thing. So I think it's best to avoid such a thing.

If anyone has a better solution, please tell me. Also I'm unsure whether this leaves some Devise stuff not tidied up in the background.




回答2:


I'm overriding the RegistrationsController create method like so:

class RegistrationsController < Devise::RegistrationsController
  def create
    if user = User.find_by_email params[:user][:email]
      user.update_attributes params[:user]
      sign_in_and_redirect user, bypass: true
    else
      super
    end
  end
end

I'm just finding the user and updating them. Devise also has a helper that combines the sign_in method with a redirect.

If no user is found then carry on as normal.



来源:https://stackoverflow.com/questions/22428680/devise-convert-an-existing-guest-user-to-a-registered-user

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!