我是ruby on rails的新手,无法完成这项工作。基本上我有一个用户注册页面,其中有密码确认。在User类中,我有以下验证:
validates :password, confirmation: true
在控制器中我有
def create
vals = params[:user]
if(User.exists(vals[:username]))
flash[:warning] = "#{vals[:username]} already exists! Please try a new one. "
else
vals[:create_date] = DateTime.current
user = User.create(vals, :without_protection => :true)
if user==false or user==nil or user==vals
flash[:warning] = "#{vals[:username]} has not been registered successfully. "
else
flash[:notice] = "#{vals[:username]} has been registered. "
end
end
redirect_to users_path
end
问题是当密码确认符合时,我仍然收到通知消息,表明注册成功。正如您所看到的,我已经为create
尝试了几个返回值,但它们似乎都没有成功。我很确定验证是有效的,因为如果密码与确认不匹配,我就看不到我刚刚创建的用户。此外,当我使用create!
时,我可以看到网站因验证错误而崩溃。任何人都可以帮助告诉我当记录未经过验证时应该返回create
的内容吗?
感谢。
答案 0 :(得分:28)
您的问题的答案是,User.create
如果成功或失败,则会返回User
个实例。如果由于验证而失败,则实例将无效并且将出错:
user.valid? # <= returns false
user.errors.count # <= will be > 0
user.errors.blank? # <= will be false
所以你的代码会改变:
if user==false or user==nil or user==vals
到此:
if !user.valid?
您也可以使用此模式:
user.attributes = vals
if user.save
... save succeeded ...
else
... save failed ...
end
save
方法返回布尔值true
或false
,因为您在现有实例上调用它。
但是,让我们通过其他几种方式让您走上正轨:
首先:你有这个:
if User.exists(vals[:username])
(我假设exits
是您放在User
模型上的一种方法,因为它不是Rails的东西。您可以在模型上使用另一个验证,而不是在控制器中进行检查:
class User < ActiveRecord::Base
...
validates :username, unique: true
...
end
现在,当您尝试创建用户时,如果您已拥有具有该名称的用户,则验证将失败。
第二:你有这个:
vals[:create_date] = DateTime.current
这是不必要的。如果您向模型添加名为created_at
的列,它将自动保留创建日期(由ActiveRecord管理)。您可以在迁移中将此及其合作伙伴updated_at
添加到您的模型中,如下所示:
create_table :users do |t|
...
t.timestamps # <= tells rails to add created_at and updated_at
end
或者,因为您已经拥有users
表:
add_column :users, :created_at, :datetime
add_column :users, :updated_at, :datetime
现在,您将始终拥有创建日期/时间以及上次更新用户模型,而无需其他代码。
第三:你有这个:
user = User.create(vals, :without_protection => :true)
不要这样做。相反,改变这个:
vals = params[:user]
对此:
vals = params.require(:user).permit(:username, :password, :password_confirmation)
然后继续保护:
user = User.create(vals)
您可以将要从表单中添加的任何其他列添加到permit()
来电。这非常重要,因为以后很难解决这类问题。 &#34;如果你走上黑暗的道路,它将永远支配你的命运。&#34;
第四:如果保存失败,则不应重定向到user_path
,因为不会显示任何用户模型。相反,您应该重新呈现您的new
表单。您也不需要Flash消息来处理错误。如果new
表单呈现,则可以检查@user.errors
并相应地报告错误消息。请参阅ActiveRecord error object documentation。
最后:您提到即使您的密码已正确确认,您的验证也会失败。我无法在不查看您的表单代码的情况下说出来,但请确保您的密码字段名为password
,并且确认字段名为password_confirmation
。在验证确认时,Rails会专门查找此*_confirmation
字段值。
如果不这样做,请发布您的表单代码并进行修改。
答案 1 :(得分:4)
答案是 ActiveRecord object
。官方源代码显示create
如果成功或失败则返回对象:
# File activerecord/lib/active_record/persistence.rb, line 29
def create(attributes = nil, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| create(attr, &block) }
else
object = new(attributes, &block)
object.save
object
end
end
如何判断成功与否
真正的答案是 persisted?
:
if user.persisted?
# Success
else
# Failed
end
为什么不使用user.valid?
来做?因为当有一些回调操作其他模型失败时,有时它是不够的:
class One < ActiveRecord::Base
has_many :twos
after_create :create_twos_after_create
def create_twos_after_create
# Use bang method in callbacks, than it will rollback while create two failed
twos.create!({}) # This will fail because lack of the column `number`
end
end
class Two < ActiveRecord::Base
validates :number, presence: true
end
现在,我们执行One.create
将失败,检查日志文件,它将是回滚,因为它无法创建两个。在这种情况下,One.create.valid?
仍会返回true
,但实际上创建失败,因此请使用One.create.persisted?
替换它。
注意:代码在Rails 5.1中进行了测试。