Проверка 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