Проверка Rails все еще запускается несмотря на то, что если опция оценивается как true

Я использую devise_invitable в моем приложении, чтобы пользователи могли отправлять приглашения. Я обнаружил плохой случай, когда пользователь был приглашен, но игнорирует приглашение и позже возвращается в приложение, чтобы зарегистрироваться самостоятельно. Так как devise_invitable обрабатывает приглашения путем создания нового user используя предоставленный адрес электронной почты для приглашения, моя проверка уникальности в поле электронной почты заставит Rails жаловаться, сообщая пользователю, что адрес электронной почты уже занят.

Я пытаюсь написать логику, чтобы справиться с этим делом. Я вижу два пути - либо найти способ обнаружить это и уничтожить ранее созданного пользователя и разрешить создание нового, либо обнаружить, что пользователь был приглашен и выполнить другой поток. Я решил реализовать второй вариант, так как хотел бы по-прежнему использовать приглашение, если это возможно.

Мой ограниченный опыт заставляет меня задаться вопросом, сработает ли то, что я написал, но я не могу на самом деле полностью проверить это, потому что проверка Rails по электронной почте инициирована. Я удостоверился, что Devise's :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 с жалобой на уникальность из-за индекса на адресе электронной почты - я не хочу разбирать все это на части, просто чтобы проверить Этот метод.

Я пытался возиться с этим часами, и я в растерянности - любая помощь приветствуется. Дайте мне знать, есть ли другой код, который вы хотите увидеть.

2 ответа

Решение

Глядя на редирект:

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

Я вижу, что нет return Это должно означать, что если этот редирект был вызван, вы должны получить AbstractController::DoubleRenderError ошибка в качестве родительского контроллера create Метод должен пытаться сделать new Посмотреть.

Исходя из этого, я думаю, что запрос, который вы используете, чтобы найти существующего пользователя, на самом деле не возвращает результат, возможно, потому что вы используете params[:email] тогда как если вы используете представления по умолчанию или правильно отформатированную форму, это должно быть params[:user][:email],

Может быть, вы должны дать больше обязанностей своему контролеру...

Если вы найдете пользователя, используйте его, иначе создайте нового. Предполагая, что ваша форма отображается с 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
Другие вопросы по тегам