对于所有弹珠来说,如果我能解决这个问题,那么我就完成了一个项目。
无论如何,我使用Ruby on Rails 3和Devise进行用户身份验证。您可能知道,默认情况下,在用户admin / edit中,如果用户提供新密码,则必须在current_password字段中输入当前密码。有关如何禁用current_password的TON信息,以便用户可以自由更改和保存。
但是,我发现相反的情况很少:要求更多字段的当前密码...在我的情况下,电子邮件字段。并且只在更改电子邮件地址时才需要当前密码,而不是在它保持不变的情况下。目前,用户可以在不提供当前密码的情况下自由更改电子邮件,出于安全考虑,我不希望这样。
在查看Devise wiki后,我确实找到this page,我认为我可以撤消此代码以完成此解决方案。我设法在我的user.rb模型中做了一点点工作(我从这篇帖子中删除了不必要的逻辑)....
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable, :lockable and :timeoutable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :name, :email, :password, :password_confirmation, :avatar, :remember_me, :agree
attr_accessor :accessible, :agree, :signed_in
attr_readonly :name
# Validation
validates :name, :presence => TRUE, :uniqueness => TRUE, :length => { :within => 4..20 }
validates :agree, :term_agreement => TRUE, :unless => :signed_in
validates_attachment_size :avatar, :less_than => 1.megabyte
validates_attachment_content_type :avatar, :content_type => ['image/jpeg', 'image/png', 'image/gif']
validates :current_password, :presence => TRUE, :if => :password_required?
protected
def password_required?
email_changed?
end
end
它“几乎”有效。如果我保存用户配置文件而不更改任何内容,或更改其他非密码必填字段(如用户头像),配置文件保存正常,无需密码。到目前为止,非常好。
如果我更改了电子邮件地址,则验证 被触发....但是会发生的情况是current_password和密码(对于新密码)字段都会根据需要触发。如果我填写所有三个密码(密码,密码_确认,current_password)只是为了它的地狱,它将不会,只是再次给出验证错误。
基本上,如果更改了电子邮件地址,则只需要current_password。我如何在我的代码中完成这项工作?
我检查了我的日志以回应bowsersenior的以下建议,并在我尝试保存和更新电子邮件时看到以下行...
User Load (0.2ms) SELECT `users`.`id` FROM `users` WHERE (LOWER(`users`.`email`) = LOWER('newaddress@changed.com')) AND (`users`.id <> 1) LIMIT 1
User Load (0.2ms) SELECT `users`.`id` FROM `users` WHERE (`users`.`name` = BINARY 'Administrator') AND (`users`.id <> 1) LIMIT 1
SQL (0.1ms) ROLLBACK
我想知道'ROLLBACK'是否与最终问题有关?
答案 0 :(得分:5)
尝试一下:
validates :current_password, :presence => TRUE, :if => :email_changed?
我强烈建议你单独留下password_required?
。这可能导致安全性和不稳定行为的错误。
答案 1 :(得分:4)
我相信Devise的做法如下:
class RegistrationsController < Devise::RegistrationsController
def update
@user = User.find(current_user.id)
successfully_updated = if needs_password?(@user, params)
@user.update_with_password(params[:user])
else
# remove the virtual current_password attribute update_without_password
# doesn't know how to ignore it
params[:user].delete(:current_password)
@user.update_without_password(params[:user])
end
if successfully_updated
set_flash_message :notice, :updated
redirect_to after_update_path_for(@user)
else
render "edit"
end
end
private
def needs_password?(user, params)
user.email != params[:user][:email]
end
end
换句话说,一切都发生在Controller级别,我们使用User#update_with_password
,当用户想要更改他的电子邮件时(我们知道通过在更新操作中调用needs_password?
)或{{1当用户更改其他个人资料数据时。
还记得你需要在路线中“注册”这个新的RegistrationsController:
User#update_without_password
来源:
答案 2 :(得分:1)
与Pawel的答案类似,但不是覆盖控制器方法更新,而是基于devise wiki
来实现这一点class RegistrationsController < Devise::RegistrationsController
protected
def update_resource(resource, params)
if resource.email != params[:email] || params[:password].present?
super
else
params.delete(:current_password)
resource.update_without_password(params)
end
end
end