设计:将现有访客用户转换为注册用户

我正在通过创建访客用户自动将每个新用户登录到站点中,如下所述:

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

这允许每个用户在我的网站上使用一些基本的东西,例如创建评论。

现在,当用户决定注册时,我想将访客用户转换为注册用户。

我试图像这样实现我自己的User.new_with_session方法:

 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 

但这不起作用。 不知何故,在提交表单时,设计似乎检测到用户已经存在于DB中,因此甚至不尝试对其进行validation等,而只是退出注册过程(因为它正在考虑用户)已经登录并转发到其他某个页面,这会导致“您需要在继续之前登录或注册”。 flash消息。

据我所知,这甚至 Devise::RegistrationsController#create被调用之前发生了。

所以这是我的问题:有没有办法告诉Devise不要仅仅因为用户已经存在于DB中而认为用户已登录(尽管我不知道Devise在提交注册表后如何了解用户) ?

更新

我可以进一步追踪问题。 每当self.new_with_session返回持久记录时,注册过程就会被取消,如上所述。 返回新对象时,注册继续。 但我无法弄清楚这在哪里检查……!?

我正在覆盖RegistrationsController创建方法,如下所示:

 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 

我只是找到用户并更新它们。 Devise还有一个帮助器,它将sign_in方法与重定向结合起来。

如果没有找到用户,则继续正常进行。

目前,我坚持以下解决方案。

我没有尝试在注册过程中将访客用户转换为注册用户,而是让Devise发挥其魔力,然后注册完成后,使用挂钩,我立即删除新注册的用户,然后我将访客用户转换为注册的,将通过用户表单提供的属性分配给前一个客人并签名。

 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 

然后在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 

通过使用update_column我确保没有触发挂钩之前/之后,否则会发生不可预测的事情,例如重新发送确认邮件(设置确认令牌时)等。

请记住,任何相关记录都不会自动从创建的@user对象传输到现有的@current_user ,因此如果您创建任何相关对象(例如在挂钩after ),则必须手动移动它们,这也是一个相当的困难的事情。 所以我认为最好避免这样的事情。

如果有人有更好的解决方案,请告诉我。 另外我不确定这是否会留下一些未在后台整理的Devise东西。