1

devise_invitable在我的应用程序中使用以允许用户发送邀请。我意识到一个糟糕的情况,用户被邀请但忽略了邀请,然后返回应用程序自行注册。因为通过使用为邀请提供的电子邮件地址devise_invitable创建一个新的邀请来处理user邀请,所以我在电子邮件字段上的唯一性验证将导致 Rails 抱怨,告诉用户该电子邮件地址已被占用。

我正在尝试编写一些逻辑来处理这种情况。我看到了两条路径——要么想办法检测到这一点并销毁先前创建的用户并允许创建新用户,要么检测到用户被邀请并执行另一个流程。我决定实施第二个选项,因为如果可能的话,我仍想使用邀请。

我有限的经验让我质疑我所写的内容是否有效,但我实际上无法完全测试它,因为触发了电子邮件上的 Rails 验证。我已确定 Devise 的:validatable模块处于非活动状态。我创建了一个方法,(我认为)将检测用户是否被邀请,在这种情况下,应该跳过唯一性验证。

#user.rb
...
validates :email, uniqueness: true, unless: :was_invited?

...
def was_invited?
  if self.invitation_sent_at.present? && self.sign_in_count == 0
    true
  else
    false
  end
end

FWIW,我最初是用速记写的,而不是打破 if/else,但我想非常明确地找到错误/失败。

希望一旦表单通过验证,该create操作将对用户的邀请状态进行一些检测,如果他们被邀请,则将他们重定向到accept_user_invitation_path. 同样,我还不能实际测试这个,因为我无法绕过验证。

#registrations_controller.rb
def create
  if User.find_by_email(params[:email])
    @existing_user = User.find_by_email(params[:email])
    @existing_user.save(validate: false)
    if @existing_user.was_invited?
      redirect_to accept_user_invitation_path(:invitation_token => @existing_user.invitation_token)
    end
  else
    super
  end
end

在拼命的努力中,您会看到我还添加了.save(validate: false)以尝试将其短路,但它甚至没有走那么远。

如果我完全注释掉电子邮件验证,只是为了测试其余的逻辑/流程,我会收到一个 PG 错误,因为电子邮件地址上的索引而抱怨唯一性 - 我不想仅仅为了测试而将所有这些拆开这种方法。

我已经尝试了好几个小时,但我很茫然 - 任何帮助表示赞赏。如果您想查看其他代码,请告诉我。

4

2 回答 2

2

查看重定向:

redirect_to accept_user_invitation_path(:invitation_token => @existing_user.invitation_token)

我可以看到没有return这应该意味着如果调用该重定向,您应该得到一个AbstractController::DoubleRenderError错误,因为父控制器的create方法应该尝试呈现new视图。

据此,我猜您用于查找现有用户的查询实际上并未返回结果,可能是因为您正在使用params[:email],而如果您使用的是默认视图或格式正确的表单,则应该是params[:user][:email].

于 2014-02-11T00:33:51.873 回答
0

也许你应该给你的控制器更多的责任......

如果您找到该用户,请使用该用户,否则创建一个新用户。假设您的表单显示为http://yourapp/users/new,请在您的路线中将其更改为http://yourapp/users/new/:email,让用户在进入表单之前输入他们的电子邮件。

def new
    @existing_user = User.find_by_email("#{params[:email]}.#{params[:format]}") || User.new
    if @existing_user.was_invited? # will only work for existing user
        redirect_to accept_user_invitation_path(:invitation_token => @existing_user.invitation_token)
    else
        render 'new'
    end
end

def create
    # do maybe something before saving
    if @existing_user.save(user_params)
        # do your magic
    else
        render 'new', notice: "Oops, I didn't save"
    end
end
于 2014-02-11T00:17:34.713 回答