为用户使用密码重置机制。密码长度验证正在触发,我试图了解原因。
user.rb
class User < ActiveRecord::Base
has_secure_password
validates :password, length: { minimum: 6 }
...
def create_password_reset_token
self.update_attributes!(password_reset_token: SecureRandom.urlsafe_base64, password_reset_sent_at: Time.zone.now)
end
def reset_password(params)
self.update_attributes!(params)
self.update_attributes!(password_reset_token: nil, password_reset_sent_at: nil)
end
end
password_resets_controller.rb
def create
user = User.find_by_email(params[:email])
if user
user.create_password_reset_token
UserMailer.password_reset_email(user).deliver
redirect_to root_url, :notice => "Email sent with password reset instructions!"
else
flash[:error] = "A user with that email address could not be found."
render 'new'
end
end
def edit
@user = User.find_by_password_reset_token(params[:id])
if @user
render 'edit'
else
flash[:error] = "Invalid password reset code."
redirect_to root_url
end
end
def update
@user = User.find_by_password_reset_token(params[:id])
if @user.password_reset_sent_at < 2.hours.ago
flash[:error] = "Password reset has expired."
redirect_to new_password_reset_path
elsif @user.reset_password(user_params)
flash[:success] = "Password has been reset."
redirect_to root_url
else
render 'edit'
end
end
password_resets / new.html.erb :
<%= form_tag password_resets_path, :method => :post do %>
<%= label_tag :email %>
<%= text_field_tag :email, params[:email] %>
<%= submit_tag "Reset Password" %>
<% end %>
password_resets / edit.html.erb:
<%= form_for @user, :url => password_reset_path(params[:id]) do |f| %>
<h1 class="centertext">Reset Password</h1>
<%= render 'shared/error_messages', object: f.object %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Update password" %>
<% end %>
错误是:
Validation failed: Password is too short (minimum is 6 characters)
抛出它的行在create_password_reset_token
方法中:
self.update_attributes!(password_reset_token: SecureRandom.urlsafe_base64, password_reset_sent_at: Time.zone.now)
为什么验证会在此处触发?我没有用密码本身做任何事情。我只是在用户记录中创建一个令牌和时间。
将验证更改为on: :create
使其不会触发。问题是,用户可以将密码重置为少于六个字符的内容。
澄清
要明确的是,操作的顺序是:
目前,验证会在输入电子邮件并单击“提交”后触发第2步。
答案 0 :(得分:0)
你的create_password_reset_token正在调用update_attributes,它将触发用户模型中每个字段的验证,从而触发密码验证,因为它没有当前的一套
你需要
1)对那些特定字段使用update_attribute并且不会触发验证
2)在模型中添加一些password_reset字段或枚举,并在单击密码重置按钮时将其设置为true,然后在用户模型中执行类似操作
has_secure_password :validations => false
validates :password, length: {minimum: 6}, unless: -> { user_password_reset? }
3)使用设计宝石来照顾你
更新
试试这个
def create_password_reset_token
self.update_attribute(:password_reset_token, SecureRandom.urlsafe_base64)
self.update_attribute(:password_reset_sent_at, Time.zone.now)
end
答案 1 :(得分:0)
我通过在密码验证中添加Proc语句来解决这个问题,如下所示:
validates :password, length: { minimum: 6 }, unless: Proc.new { |a| !a.password_reset_token.nil? }
现在验证在用户创建和密码重置期间运行,但在设置密码重置令牌的时间间隔内不运行。所有测试都在通过。