1

アプリで使用devise_invitableして、ユーザーが招待状を送信できるようにします。ユーザーが招待されたにもかかわらず、招待を無視し、後でアプリに戻って自分でサインアップするという悪いケースに気付きました。devise_invitable招待用に提供された電子メール アドレスを使用して新しい を作成することで招待を処理するためuser、電子メール フィールドで一意性を検証すると、Rails が不平を言い、電子メール アドレスが既に使用されていることをユーザーに伝えます。

このケースを処理するためのロジックを書き込もうとしています。これを検出して以前に作成したユーザーを破棄し、新しいユーザーを作成できるようにするか、ユーザーが招待されたことを検出して別のフローを実行するかの 2 つのパスが表示されます。可能であれば引き続き招待状を利用したいので、2 番目のオプションを実装することにしました。

私の限られた経験では、私が書いたものが機能するかどうか疑問に思っていますが、電子メールの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

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 に答える