Я работаю над мультивендорной аутентификацией в приложении Ruby on Rails, используя Devise и omniauth - *.
Я, в основном, следовал по этой ссылке за исключением omniauth_callbacks_controller.rb
, где я добавил:
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def after_sign_in_path_for(resource)
if resource.email_verified?
super resource
else
finish_signup_path(resource)
end
end
def all
puts request.env["omniauth.auth"]
user = User.find_for_oauth(request.env["omniauth.auth"], current_user)
if user.persisted?
sign_in_and_redirect user, notice: "Signed in!"
else
session["devise.all"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
alias_method :twitter, :all
alias_method :google_oauth2, :all
alias_method :facebook, :all
alias_method :instagram, :all
end
и app/models/user.rb
Я изменил self.find_for_oauth
на:
def self.find_for_oauth(auth, signed_in_resource = nil)
identity = Identity.find_for_oauth(auth)
user = signed_in_resource ? signed_in_resource :identity.user
if user.nil?
email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email)
email = auth.info.email || if auth.info.nickname then auth.info.nickname + "@twitter.org" end
user = User.where("email = ?", email).first if email
if user.nil?
user = User.new(
first_name: auth.extra.raw_info.name,
email: if auth.info.email != nil and auth.info.email != "" then auth.info.email else if auth.info.nickname then auth.info.nickname + "@twitter.org" end end ,
password: Devise.friendly_token[0, 20]
)
user.skip_confirmation!
user.save!
end
end
if identity.user != user
identity.user = user
identity.save!
end
user
end
Мне удалось сделать так, чтобы пользователь мог войти в систему с помощью различных социальных сетей, созданных с одним и тем же адресом электронной почты, создав модель identity
, в которой user
has_many identities
.
Однако сейчас я не могу подписаться (с помощью электронной почты и паролей) на электронное письмо, которое уже было получено объектом user
, созданным с помощью социальных сетей.
Как я могу решить эту проблему?
UPDATE
Подход, который я сейчас пробую, заключается в проверке того, выполнил ли пользователь ранее такой же адрес электронной почты. Если это так, учетная запись пользователя должна быть обновлена с регистрационными данными и предоставлена для более identity
объекта с provider
, установленным пустым.
ОБНОВЛЕНИЕ 2
Теперь я могу зарегистрировать пользователя по электронной почте и паролю, настроив метод create
в registrations_controller.rb
на:
def create
build_resource(sign_up_params)
resource[:provider] = "<default provider>"
if !User.find_by_email(resource.email) then
resource.save
yield resource if block_given?
if resource.persisted?
if resource.active_for_authentication?
set_flash_message! :notice, :signed_up
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
set_flash_message! :error, :"Something went wrong"
clean_up_passwords resource
set_minimum_password_length
respond_with resource
end
else
user = User.find_by_email(resource.email)
if user.identities.count > 0 and user.provider != "<default provider>" then
@identity = Identity.new
@identity.provider = "made up provider"
@identity.save
user.password = resource.password
if resource.country != nil and resource.country != "" then
user.country = resource.country
end
if resource.title != nil and resource.title != "" then
if resource.title != nil and resource.title != "" then
user.title = resource.title
end
if resource.first_name != nil and resource.first_name != "" then
user.first_name = resource.first_name
end
if resource.last_name != nil and resource.last_name != "" then
user.last_name = resource.last_name
end
if resource.phone_number != nil and resource.phone_number != "" then
user.phone_number = resource.phone_number
end
if resource.country_code != nil and resource.country_code != "" then
user.country_code = resource.country_code
end
user.provider = "<default provider>"
user.save
yield user if block_given?
if user.persisted?
if resource.active_for_authentication?
set_flash_message! :notice, :signed_up
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(user)
end
else
set_flash_message! :error, :"Something went wrong"
clean_up_passwords resource
set_minimum_password_length
respond_with resource
end
else
set_flash_message! :error, "This Account already exists"
redirect_to new_user_session_path
end
end
Тем не менее, сообщение с «письмом-подтверждением отправлено на вашу электронную почту», в то время как письмо-подтверждение не отправлено.
Как я могу заставить его отправлять подтверждение по электронной почте, когда пользователь вводит пароль впервые (регистрация пользователя с электронной почтой и паролем)?
Update3
Мой текущий вопрос:
Используя Devise, как я могу отправить электронное письмо с подтверждением (идентично электронному письму с подтверждением регистрации) при первом обновлении пароля (или о конкретном действии)?