创建失败时 Ruby on Rails Active Record 返回值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23975835/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ruby on Rails Active Record return value when create fails?
提问by zyl1024
I am new to ruby on rails and having trouble getting this work. Basically I have a user registration page which has a password confirmation. In the User class I have the following validation:
我是 ruby on rails 的新手,无法完成这项工作。基本上我有一个用户注册页面,其中有一个密码确认。在 User 类中,我有以下验证:
validates :password, confirmation: true
And in the controller I have
在控制器中我有
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
The problem is that when the password does match the confirmation, I am still getting the notice message showing that the registration is successful. As you can see I have tried several return values for createbut none of them seems to succeed. I am pretty sure that the validation is working because I cannot see the user that I just created if password does not match with confirmation. In addition, when I use create!, I can see the website crashes with the validation error. Can anyone help telling me what createshould return when the record is not validated?
问题是当密码确实与确认匹配时,我仍然收到显示注册成功的通知消息。如您所见,我尝试了几个返回值,create但似乎没有一个成功。我很确定验证正在工作,因为如果密码与确认不匹配,我将看不到我刚刚创建的用户。此外,当我使用 时create!,我可以看到网站因验证错误而崩溃。任何人都可以帮助告诉我create当记录未经验证时应该返回什么?
Thanks.
谢谢。
回答by gwcoffey
The answer to your question is, User.createreturns a Userinstance if it succeeds orfails. If it fails because of validations, the instance will be invalid and will have errors:
您的问题的答案是,如果成功或失败,则User.create返回一个User实例。如果由于验证而失败,则实例将无效并且会出现错误:
user.valid? # <= returns false
user.errors.count # <= will be > 0
user.errors.blank? # <= will be false
So your code would change from this:
所以你的代码将从这里改变:
if user==false or user==nil or user==vals
to this:
对此:
if !user.valid?
You can also use this pattern:
你也可以使用这个模式:
user.attributes = vals
if user.save
... save succeeded ...
else
... save failed ...
end
The savemethod returns a boolean trueor falsesince you are calling it on an existing instance.
该save方法返回一个布尔值,true或者false因为您在现有实例上调用它。
But lets get you on the right track in a few other ways:
但是让我们通过其他一些方式让您走上正轨:
First:you have this:
第一:你有这个:
if User.exists(vals[:username])
(I'm assuming exitsis a method you put on your Usermodel because that's not a Rails thing). Instead of doing that check in your controller, you can just use another validation on the model:
(我假设exits是您在User模型上放置的一种方法,因为那不是 Rails 的东西)。您可以在模型上使用另一个验证,而不是在您的控制器中进行检查:
class User < ActiveRecord::Base
...
validates :username, unique: true
...
end
Now when you try to create the user, it will fail validation if you already have one with that name.
现在,当您尝试创建用户时,如果您已经拥有一个具有该名称的用户,则验证将失败。
Second:You have this:
第二:你有这个:
vals[:create_date] = DateTime.current
This is unnecessary. If you add a column to your model called created_atit will hold the creation date automatically (managed by ActiveRecord). You can add this, and its partner updated_atto your model in your migration like this:
这是不必要的。如果您向模型中添加一列,created_at它会自动保存创建日期(由 ActiveRecord 管理)。您可以updated_at在迁移中将其及其合作伙伴添加到您的模型中,如下所示:
create_table :users do |t|
...
t.timestamps # <= tells rails to add created_at and updated_at
end
Or, since you already have a userstable:
或者,因为您已经有一张users桌子:
add_column :users, :created_at, :datetime
add_column :users, :updated_at, :datetime
Now you will always have the date/time of creation and last update on your user model with no need for additional code.
现在,您将始终拥有用户模型的创建日期/时间和上次更新,无需额外代码。
Third:You have this:
第三:你有这个:
user = User.create(vals, :without_protection => :true)
Don't do this. Instead, change this:
不要这样做。相反,改变这个:
vals = params[:user]
To this:
对此:
vals = params.require(:user).permit(:username, :password, :password_confirmation)
And then keep protection on:
然后继续保护:
user = User.create(vals)
You can add any additional columns you want to bring from your form to the permit()call. This is very important because it is hard to fix this kind of thing later. "If once you go down the dark path, forever will it dominate your destiny."
您可以添加要从表单中引入的任何其他列到permit()调用中。这很重要,因为以后很难修复这种事情。“一旦你走上黑暗之路,它将永远主宰你的命运。”
Fourth:You should not redirect to the user_pathif the save failed, because there will be no user model to show. Instead you should re-render your newform. You also don't need flash messages for the errors. If the newform renders, it can check @user.errorsand report error messages accordingly. See the ActiveRecord error object documentation.
第四:user_path如果保存失败,您不应该重定向到,因为将不会显示用户模型。相反,您应该重新渲染您的new表单。对于错误,您也不需要 Flash 消息。如果new表单呈现,它可以相应地检查@user.errors和报告错误消息。请参阅ActiveRecord 错误对象文档。
Finally:You mention that you your validation fails even when your password is properly confirmed. I can't say for sure without seeing your form code, but make sure your password field is called passwordand the confirmation field is called password_confirmation. Rails looks for this *_confirmationfield value specifically when validating for confirmation.
最后:您提到即使正确确认您的密码,您的验证也会失败。如果没有看到您的表单代码,我无法确定,但请确保您的密码字段被调用password并且确认字段被调用password_confirmation。Rails*_confirmation在验证确认时专门查找此字段值。
If that doesn't do it, post your form code and I'll revise.
如果那不这样做,请发布您的表单代码,我会修改。
回答by songhuangcn
The answer is the ActiveRecord object. The official source code shows that createreturn the object if it succeeds or fails:
答案是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
How to judge it succeeds or fails
如何判断成功或失败
The real answer is persisted?:
真正的答案是persisted?:
if user.persisted?
# Success
else
# Failed
end
Why didn't use user.valid?to do it? Because sometimes it is not enough when there are some callbacks which operate other models failed:
为什么不习惯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
Now, we execute One.createwill fail, check the log file, it will be a rollback because it failed to create two. In this case, One.create.valid?still return true, but it actually created failed, so use One.create.persisted?to replace it is necessary.
现在,我们执行One.create会失败,检查日志文件,它会回滚,因为它创建了两个失败。在这种情况下,One.create.valid?仍然 return true,但它实际上创建失败了,所以使用One.create.persisted?来替换它是必要的。
Notice: The code is tested in Rails 5.1.
注意:代码在 Rails 5.1 中测试。

