我的表格包含字段:email
,password_hash
和salt
。
在用户注册时,我想验证密码和密码确认,但我总是收到can't be blank
的密码输入错误。
这是我的模特:
attr_accessor :password
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
我是guest我不能验证不是数据库的字段,而是如何对用户输入的密码进行验证?
我在数据库中没有密码字段,因为我知道我得到的password
输入,然后我将它存储在db password_hash
字段中。
编辑:
这是数据库表:
class CreateStudents < ActiveRecord::Migration
def change
create_table :students do |t|
t.string :first_name
t.string :last_name
t.string :email
t.string :password_hash
t.string :salt
t.boolean :activated
t.timestamps
end
end
end
这是注册视图:
<%= form_for @student, url: {action: 'create'} do |form| %>
<p style="font-size:smaller; color:red">
<% @student.errors.messages.each do |att, msg| %>
<%= msg[0] %><br>
<% end %>
<p>
<%= form.label :first_name %><br>
<%= form.text_field :first_name %>
<p>
<%= form.label :last_name %><br>
<%= form.text_field :last_name %>
<p>
<%= form.label :email %><br>
<%= form.text_field :email %>
<p>
<%= form.label :password %><br>
<%= form.password_field :password %>
<p>
<%= form.label :password_confirmation %><br>
<%= form.password_field :password_confirmation %>
<p>
<%= form.submit %>
<% end %>
这是控制器:
def sing_up
@student = Student.new
render 'sing_up'
end
def create
@student = Student.new
@student.first_name = params[:student][:first_name]
@student.last_name = params[:student][:last_name]
@student.email = params[:student][:email]
@student.salt = BCrypt::Engine.generate_salt
@student.password_hash = BCrypt::Engine.hash_secret(params[:student][:password], @student.salt)
if @student.save
redirect_to controller: 'singups', action: 'index'
else
render 'sing_up'
end
end
和finnaly,这是模型
class Student < ActiveRecord::Base
attr_accessor :password
validates :first_name, :length => { minimum: 3, message: "first_name" }
validates :last_name, :length => { minimum: 3, message: "last_name" }
validates :email, :presence => { message: 'email' },
:format => { with: /\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+\z/ , message: 'email format' },
:uniqueness => { message: 'uniqueness?' }
validates :password, :confirmation => { message: 'password' },
:length => { minimum: 6, message: 'password length' }
end
每次用户输入密码时,无论密码是什么,它都会在首次验证:confirmation => { message: 'password' }
时失败。
如果删除validates :password
部分,一切正常,但用户输入的密码未经过验证。
答案 0 :(得分:3)
您正在验证用户的password
属性,但您从未在第一时间为其指定值。至少,您需要将其添加到控制器代码中:
@student.password = params[:student][:password]
@student.password_confirmation = params[:student][:password_confirmation]
然而,更简洁的方法是使用质量分配 - 摆脱所有@ student.xxx = yyy并将其替换为:
@student = Studen.new(params[:student])
然后,将密码哈希方法移动到模型中,并在每次保存之前自动触发它,如果密码属性存在:
class User < ActiveRecord::Base
# ...
before_save :hash_password, :if => proc{ |u| !u.password.blank? }
# ....
protected
def hash_password
self.salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, salt)
end
end
这样你就不需要在控制器中做任何事了,但是这个:
def create
@student = Student.new(params[:student])
if @student.save
redirect_to controller: 'singups', action: 'index'
else
render 'sing_up'
end
end
并在模型中包含所有其他逻辑。
编辑:为了使批量分配能够与最新版本的Rails 3一起使用,您需要像attr_accessible
那样创建要分配的属性,如下所示:
class Student < ActiveRecord::Base
# ...
attr_accessible :first_name, :last_name, :email, :password # but NOT the hash or salt!!
end
答案 1 :(得分:1)
你应该从头开始查看处理真实性的Railscast,所有内容都在这里解释http://railscasts.com/episodes/250-authentication-from-scratch
这里有一个更新的演员http://railscasts.com/episodes/250-authentication-from-scratch-revised,但您需要订阅才能查看(非常值得IMO)
答案 2 :(得分:0)
您需要将用户输入的密码转换为加密值,然后将加密值与password_hash中的值进行比较,以查看它们是否匹配。这就是您验证用户是否是正确用户的方式。如果您的模型没有密码字段(它不应该),这并不重要,因为您不直接比较密码中的值。
有不同的加密方式,但重要的是你如何将原始密码首先加密到password_hash(你是如何生成'password_hash'的?)。使用相同的方法检查新密码提交。
答案 3 :(得分:0)
您可以通过自定义验证来检查密码和password_confirmation。
class User< ActiveRecord::Base
attr_accessor :password, :password_confirmation
validate :valid_password
def valid_password
if password.blank? || password_confirmation.blank?
errors.add(:password, 'password must not be blank')
end
if password != password_confirmation
errors.add(:password, 'password and confirmation does not match')
end
end
end
这样,它会检查密码和确认是否存在并且同时存在。