Rails在提交空表单时不返回验证错误
问题描述:
简而言之:我有一个设计模型用户我为用户添加一个选项,以便能够在其个人档案页面中更改其密码,而无需通过“忘记密码”选项。总之,因为这需要有领域的另一种形式::old_password, :new_password and :new_password_confirmation
未原先模型,我不得不为他们创造新的独立验证,Rails在提交空表单时不返回验证错误
形式:
<%= form_for(@user, :url => {:controller => :members, :action => :editpass}, :html => {:method => :post}) do |f| %>
<input name="authenticity_token" type="hidden" value="<%= form_authenticity_token %>">
<table class="tables no-border">
<tr>
<%= f.label :old_password, "Old password" %>
</tr>
<tr>
<%= f.password_field :old_password, :autofocus => :true %>
</tr>
<tr>
<%= f.label :new_password, "New password" %>
</tr>
<tr>
<%= f.password_field :new_password %>
</tr>
<tr>
<%= f.label :new_password_confirmation, "Repeat new password" %>
</tr>
<tr>
<%= f.password_field :new_password_confirmation %>
</tr>
<tr>
<input type="submit" value="Change" class="btn" />
</tr>
</table>
</form>
<%= @user.errors.full_messages %>
<% end %>
控制器:
class MembersController < ApplicationController
before_filter :authenticate_user!
skip_before_filter :check_for_main
def index
@users = User.all
end
def show
@user = User.find(params[:id])
end
def editpass
current_user.change_password(params[:old_password], params[:new_password])
redirect_to member_path(current_user.id)
end
# User access restriction
def ban
end
def unban
end
end
型号:查看:验证领域:old_password /:new_password ..
class User < ActiveRecord::Base
# Virtual attributes
# _password attributes serve in-profile password change and are not part of the model
attr_accessor :login, :apiid, :vcode, :old_password, :new_password, :new_password_confirmation
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable, :confirmable,
:recoverable, :rememberable, :trackable, :validatable, :authentication_keys => [:login]
# Registration show/edit form validation
validates :username, :presence => true,
:length => { :minimum => 6, :maximum => 255 },
:uniqueness => true
validates :apiid, :presence => true,
:numericality => { :only_integer => true },
:acc_api => true,
:on => :create
validates :vcode, :presence => true,
:length => { :minimum => 20, :maximum => 255 },
:on => :create
# In profile password
validates :old_password, :presence => true,
:length => { :minimum => 8, :maximum => 255 },
:if => :password_changed?
validates :new_password, :presence => true,
:length => { :minimum => 8, :maximum => 255 },
:if => :password_changed?,
:confirmation => true
validates :new_password_confirmation,
:presence => true
attr_accessible :login, :username, :group, :apiid, :vcode, :email, :password, :password_confirmation, :remember_me
# Register character belonging to user
after_create :register_characters
# Model association
has_many :apis
has_many :characters
# Allows user to reset password in profile
# for Forgot Password look at Devise
def change_password(oldpass, newpass)
if self.valid_password?(oldpass)
# User is logged out automatically by devise upon
# password change
self.password = newpass
self.save
else
return false
end
end
# Register account characters
def register_characters
require 'nokogiri'
require 'open-uri'
# Fetch account level xml
uri = "https://api.eveonline.com/account/Characters.xml.aspx?keyID=#{self.apiid}&vCode=#{self.vcode}"
xml = Nokogiri::XML(open(uri))
row = xml.xpath("//row")
# Create characters bound to user
row.each do |entry|
# Register new character
character = Character.new(
:charid => entry['characterID'].to_i,
:user_id => self.id,
:name => entry['name'],
:corp => entry['corporationName']
)
character.save
# Register character associated api credentials
api = Api.new(
:user_id => self.id,
:character_id => character.id,
:apiid => self.apiid,
:vcode => self.vcode
)
api.save
character.update_character
end
end
# Check if user is banned before login
def active_for_authentication?
super && self.banned == false
end
# Redefine authentication procedure to allow login with username or email
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login).downcase
where(conditions).where("username = '#{login}' OR email = '#{login}'").first
else
where(conditions).first
end
end
end
答
基本上,你的密码验证不被达到。
使用change_password
方法,您只是将值从控制器传递到该方法并使用它们来设置password
。该模型没有看到old_password
和new_password
被设置,所以它不能验证它们。另外,由于您没有通过password_confirmation
并直接在模型中设置密码(self.password = newpass
),所以也没有使用password_confirmation
。
正如在另一个答案中提到的,你最好使用update_attributes
或Devise文档中推荐的任何东西。希望我的解释能够为您的方法不起作用添加一些洞见。
如果您想坚持您的change_password
方法,您必须将值传递给属性,以便它们可以通过模型进行验证。尝试是这样的:
#controller
@user = current_user
if @user.change_password(params[:old_password], params[:new_password], params[:new_password_confirmation])
redirect_to member_path(current_user.id)
else
@errors = @user.errors.full_messages
render 'edit_password_view' # not sure what this action is named
# you now have an array of errors (@errors) that you can render however you see fit in the view
end
#model
def change_password(oldpass, newpass, newpass_conf)
self.password = newpass
self.old_password = oldpass
self.new_password = newpass
self.new_password_confirmation = newpass_conf
return self.save
end
答
我认为正确的方法是更新用户属性,而不是使用更改密码。也许这个指南能有所帮助:
https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-edit-their-password
我之所以说是因为如果我提交表单只有那些密码字段我将获得的用户名,VCODE,apiid验证错误.. – 2013-03-27 21:44:39
看着深入到你的代码,更新了我的答案。希望有所帮助。 – aguynamedloren 2013-03-27 21:54:19
change_mathod不是它工作的问题。问题是与old_password/new_password等。我如何设置这些来验证它们? – 2013-03-27 21:56:17