Ruby on Rails创建失败时的Active Record返回值?

我是ruby on rails的新手,无法完成这项工作。 基本上我有一个用户注册页面,其中有密码确认。 在User类中,我有以下validation:

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尝试了几个返回值,但它们似乎都没有成功。 我很确定validation是有效的,因为如果密码与确认不匹配,我就看不到我刚创建的用户。 另外,当我使用create! ,我可以看到网站因validation错误而崩溃。 任何人都可以帮助告诉我在未validation记录时应该返回什么create

谢谢。

您的问题的答案是, User.create返回User实例,如果它成功失败。 如果由于validation而失败,则实例将无效并且将出错:

 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方法返回布尔值truefalse因为您在现有实例上调用它。

但是,让我们通过其他几种方式让您走上正轨:

第一:你有这个:

 if User.exists(vals[:username]) 

(我假设exits是你放在User模型上的一种方法,因为那不是Rails的事情)。 您可以在模型上使用另一个validation,而不是在控制器中进行检查:

 class User < ActiveRecord::Base ... validates :username, unique: true ... end 

现在,当您尝试创建用户时,如果您已经拥有该名称,则validation将失败。

第二:你有这个:

 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()调用。 这非常重要,因为以后很难解决这类问题。 “如果你走上黑暗的道路,它将永远支配你的命运。”

第四:如果保存失败,则不应重定向到user_path ,因为不会显示用户模型。 相反,您应该重新渲染new表单。 您也不需要错误的flash消息。 如果new表单呈现,它可以检查@user.errors并相应地报告错误消息。 请参阅ActiveRecord错误对象文档 。

最后:即使您的密码已正确确认,您也提到您的validation失败。 如果没有看到您的表单代码,我无法确定,但请确保您的密码字段名为password ,确认字段名为password_confirmation 。 在validation确认时,Rails会专门查找此*_confirmation字段值。

如果不这样做,请发布您的表单代码,我将进行修改。

答案是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中测试。