致力于更新一些旧版设计代码(不会使用devise_invitable
)并遭受不可避免的头痛。
所需的功能是避免交付Devise的确认电子邮件,直到管理员实际邀请给定用户为止。
在devise/registrations#new
上有一个表单,用户输入他们的电子邮件,管理员后端,最终是users#index
,其中有一个"邀请按钮"
近年来,由于设计管理信息中心中的遗留业务逻辑会查找没有~> 4.1.1
的用户,因此设计似乎已经发生了变化(应用目前处于confirmation_token
)。并询问管理员是否要向这些用户发送邀请。
<%=(user.confirmation_token.nil? ?
(link_to "Send Invitation", invite_user_path(user.id), {:class => 'button radius tiny'}) :
(link_to "Resend", invite_user_path(user.id), {:class => 'button radius tiny'})) unless user.confirmed_at.present?
%>
这是User
模型,其中包含许多方法,旨在覆盖默认的逻辑设计用于验证和创建用户。
class User < ActiveRecord::Base
...
devise :database_authenticatable, :registerable,
:confirmable, :recoverable, :rememberable,
:trackable, :validatable
has_and_belongs_to_many :roles, :join_table => :roles_users
after_create :add_role
def password_required?
if !persisted?
!(password != "")
else
!password.nil? || !password_confirmation.nil?
end
end
# override Devise method
def confirmation_required?
false
end
# override Devise method
def active_for_authentication?
confirmed? || confirmation_period_valid?
end
def send_reset_password_instructions
if self.confirmed?
super
else
errors.add :base, "You must receive an invitation before you set your password."
end
end
# new function to set the password
def attempt_set_password(params)
p = {}
p[:password] = params[:password]
p[:password_confirmation] = params[:password_confirmation]
update_attributes(p)
end
# new function to determine whether a password has been set
def has_no_password?
self.encrypted_password.blank?
end
# new function to provide access to protected method pending_any_confirmation
def only_if_unconfirmed
pending_any_confirmation {yield}
end
private
def add_role
return if roles.pluck(:name).include? "partner"
free = Role.find_by_name "free"
roles << free
save!
end
end
在prod上修改后,似乎立即创建了确认令牌,就像创建User
记录时一样。
2016-06-06T21:49:19.283289+00:00 app[web.1]:
SQL (27.9ms)
UPDATE `users`
SET `created_at` = '2016-06-06 21:49:19.172495',
`updated_at` = '2016-06-06 21:49:19.172495',
`id` = 37,
`unconfirmed_email` = 'adminemail@gmail.com',
`confirmation_token` = 'bdyrKwZG31mPtfAskEsU',
`confirmation_sent_at` = '2016-06-06 21:49:19.252215'
WHERE `users`.`id` = 37
有趣的是,它并非100%明确表示电子邮件实际正在发送,但我只是想了解为什么确认令牌(和confirmation_sent_at
)仍然存在立即更新。那是一个错误吗?这是新的吗?或者我错了吗?
包括ConfirmationsController
意大利面条代码也是为了您的观赏乐趣:
class ConfirmationsController < Devise::PasswordsController
# Remove the first skip_before_filter (:require_no_authentication) if you
# don't want to enable logged users to access the confirmation page.
# skip_before_filter :require_no_authentication
skip_before_filter :authenticate_user!
# POST /resource/confirmation
def create
self.resource = resource_class.send_confirmation_instructions(resource_params)
if successfully_sent?(resource)
respond_with({}, :location => after_resending_confirmation_instructions_path_for(resource_name))
else
respond_with(resource)
end
end
# PUT /resource/confirmation
def update
with_unconfirmed_confirmable do
if @confirmable.has_no_password?
@confirmable.attempt_set_password(resource_params)
if @confirmable.valid?
@confirmable.update_attributes!(resource_params)
do_confirm
else
do_show
@confirmable.errors.clear #so that we won't render :new
end
else
self.class.add_error_on(self, :email, :password_allready_set)
end
end
if !@confirmable.errors.empty?
render 'devise/confirmations/new'
end
end
# GET /resource/confirmation?confirmation_token=abcdef
def show
with_unconfirmed_confirmable do
if @confirmable.has_no_password?
do_show
else
do_confirm
end
end
if !@confirmable.errors.empty?
render 'devise/confirmations/new'
end
end
protected
def with_unconfirmed_confirmable
@confirmable = User.find_or_initialize_with_error_by(:confirmation_token, params[:confirmation_token])
self.resource = @confirmable
if !@confirmable.new_record?
@confirmable.only_if_unconfirmed {yield}
end
end
def do_show
@confirmation_token = params[:confirmation_token]
@requires_password = true
render 'devise/confirmations/show'
end
def do_confirm
@confirmable.confirm!
set_flash_message :notice, :confirmed
sign_in_and_redirect(resource_name, @confirmable)
end
# The path used after resending confirmation instructions.
def after_resending_confirmation_instructions_path_for(resource_name)
new_session_path(resource_name)
end
# The path used after confirmation.
def after_confirmation_path_for(resource_name, resource)
after_sign_in_path_for(resource)
end
private
def resource_params
params.require(:user).permit(:first_name, :last_name, :email, :encrypted_password, :reset_password_token, :reset_password_sent_at, :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip, :created_at, :updated_at, :confirmation_token, :confirmed_at, :confirmation_sent_at)
end
end
也添加RegistrationsController
:
class Users::RegistrationsController < Devise::RegistrationsController
def new
super
end
def create
session[:email] = params[:user][:email] if params[:user][:email]
if User.exists?(email: params[:user][:email])
redirect_to :public_feed, flash: { notice: "Welcome back." }
else
super
end
end
end