错误不会阻止对象保存?

时间:2011-08-26 06:07:40

标签: ruby-on-rails ruby

我有一个虚拟属性,它从表单字段中获取时间范围并将其拆分:

def time_range=(time_range)
  unless time_range.empty?
    t = time_range.split(/to|\-/)
    self.start_entry = t[0]
    self.finish_entry = t[1]
    if Chronic.parse(self.start_entry).nil? || Chronic.parse(self.finish_entry).nil?
      errors.add(:time_range, 'Invalid time range entered')
    end
  end
end

start_entryfinish_entry也是虚拟属性,因为我有其他方法来设置它们。无论两者是如何设置的,我都有以下钩子在我的数据库中设置startfinish

before_save :set_start_and_finish

尽管我添加了错误,但错误的对象仍设法保存:

> t = Tour.new
> t.time_range = "rubbish"
> t.errors
#=> {:time_range=>["Invalid time range entered"]}
> t.valid?
#=> true

如何使实例无效以防止以后保存?

3 个答案:

答案 0 :(得分:14)

调用t.valid?将在运行验证之前清除错误,以便忽略time_range=内的验证。

如果我们查看ActiveRecords's valid?,我们会看到:

def valid?(context = nil)
  context ||= (new_record? ? :create : :update)
  output = super(context)
  #...

超级人员应该把你送到ActiveModel's valid?,就像这样开始:

def valid?(context = nil)
  current_context, self.validation_context = validation_context, context
  errors.clear
  #...

并且clear来电会核实您在time_range=中添加的错误。

如果要验证某些内容,请使用验证器。如果您想阻止无效的分配,请提出ArgumentError(或其他更合适的例外情况)。

在运行验证之前让验证系统自行重置(即errors.clear)确实有意义。如果它没有重置,你必须扔掉并重新加载一个无效的对象(或手动重置它)只是为了纠正验证错误。仅仅因为“更新,验证,保存或销毁”是Web应用程序的一般工作流程并不意味着它是数据库支持的应用程序唯一可能的工作流程。

答案 1 :(得分:1)

set_start_and_finish似乎是一个检查验证错误的奇怪地方,但如果检测到错误以阻止其余回调执行,请确保返回false

Read the section on "Cancelling callbacks"

答案 2 :(得分:0)

尝试在验证时调用set_start_and_finish而不是before_savevalidate :set_start_and_finish