zyl*_*024 14 ruby activerecord ruby-on-rails rails-activerecord
我是ruby on rails的新手,无法完成这项工作.基本上我有一个用户注册页面,其中有密码确认.在User类中,我有以下验证:
validates :password, confirmation: true
Run Code Online (Sandbox Code Playgroud)
在控制器中我有
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
Run Code Online (Sandbox Code Playgroud)
问题是,当密码确认符合时,我仍然收到通知消息,表明注册成功.正如你所看到的,我已经尝试了几个返回值,create但它们似乎都没有成功.我很确定验证是有效的,因为如果密码与确认不匹配,我就看不到我刚刚创建的用户.另外,当我使用时create!,我可以看到网站因验证错误而崩溃.任何人都可以帮助告诉我create在未经过验证的情况下应该返回什么内容吗?
谢谢.
gwc*_*fey 33
您的问题的答案是,如果成功成功或失败,则User.create返回User实例.如果由于验证而失败,则实例将无效并将出现错误:
user.valid? # <= returns false
user.errors.count # <= will be > 0
user.errors.blank? # <= will be false
Run Code Online (Sandbox Code Playgroud)
所以你的代码会改变:
if user==false or user==nil or user==vals
Run Code Online (Sandbox Code Playgroud)
对此:
if !user.valid?
Run Code Online (Sandbox Code Playgroud)
您也可以使用此模式:
user.attributes = vals
if user.save
... save succeeded ...
else
... save failed ...
end
Run Code Online (Sandbox Code Playgroud)
该save方法返回一个布尔值,true或者false因为您在现有实例上调用它.
但是,让我们通过其他几种方式让您走上正轨:
第一:你有这个:
if User.exists(vals[:username])
Run Code Online (Sandbox Code Playgroud)
(我假设exits你的User模型是一种方法,因为那不是Rails的东西).您可以在模型上使用另一个验证,而不是在控制器中进行检查:
class User < ActiveRecord::Base
...
validates :username, unique: true
...
end
Run Code Online (Sandbox Code Playgroud)
现在,当您尝试创建用户时,如果您已经拥有该名称,则验证将失败.
第二:你有这个:
vals[:create_date] = DateTime.current
Run Code Online (Sandbox Code Playgroud)
这是不必要的.如果向模型添加一个名为的列,created_at它将自动保存创建日期(由ActiveRecord管理).您可以updated_at在迁移中将此及其合作伙伴添加到模型中,如下所示:
create_table :users do |t|
...
t.timestamps # <= tells rails to add created_at and updated_at
end
Run Code Online (Sandbox Code Playgroud)
或者,因为你已经有一张users桌子:
add_column :users, :created_at, :datetime
add_column :users, :updated_at, :datetime
Run Code Online (Sandbox Code Playgroud)
现在,您将始终拥有创建日期/时间以及上次更新用户模型,而无需其他代码.
第三:你有这个:
user = User.create(vals, :without_protection => :true)
Run Code Online (Sandbox Code Playgroud)
不要这样做.相反,改变这个:
vals = params[:user]
Run Code Online (Sandbox Code Playgroud)
对此:
vals = params.require(:user).permit(:username, :password, :password_confirmation)
Run Code Online (Sandbox Code Playgroud)
然后继续保护:
user = User.create(vals)
Run Code Online (Sandbox Code Playgroud)
您可以将要从表单中添加的任何其他列添加到permit()调用中.这非常重要,因为以后很难解决这类问题."如果你走上黑暗的道路,它将永远支配你的命运."
第四:user_path如果保存失败,则不应重定向到,因为不会显示用户模型.相反,你应该重新渲染你的new表格.您也不需要错误消息.如果new表单呈现,它可以相应地检查@user.errors和报告错误消息.请参阅ActiveRecord错误对象文档.
最后:即使您的密码已得到正确确认,您也提到您的验证失败.如果没有看到您的表单代码,我无法确定,但请确保调用您的密码字段并调用password确认字段password_confirmation.*_confirmation在验证确认时,Rails会专门查找此字段值.
如果不这样做,请发布您的表单代码,我将进行修改.
答案是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
Run Code Online (Sandbox Code Playgroud)
如何判断它成功还是失败
真正的答案是persisted?:
if user.persisted?
# Success
else
# Failed
end
Run Code Online (Sandbox Code Playgroud)
为什么不习惯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
Run Code Online (Sandbox Code Playgroud)
现在,我们执行One.create将失败,检查日志文件,这将是一个回滚,因为它无法创建两个。在这种情况下,One.create.valid?仍然会返回true,但实际上创建失败,因此One.create.persisted?有必要使用它来替换它。
注意:该代码已在Rails 5.1中进行了测试。
| 归档时间: |
|
| 查看次数: |
23180 次 |
| 最近记录: |