Rails ActiveRecord回调

时间:2014-01-24 23:40:10

标签: ruby-on-rails ruby activerecord

我遇到日期格式问题。我有一个时间选择器,它有一个时髦的格式的日期(嗯,这是一个很好的格式,实际上,但不是计算机)。我正在尝试Chronic解析日期,以便可以正确保存。

起初,我在控制器的创建动作中正在做:

params[:event][:start] = Chronic.parse(params[:event][:start])

但是如果验证失败,它会将解析后的值发送回视图,然后我的datetimepicker全部被拙劣。

所以,我想......回调?在我的模型中,我补充道:

private
  def date_change
    self.start = Chronic.parse(self.start)
  end

我尝试了before_savebefore_validationafter_validation ...但似乎没有任何东西可以正确格式化日期。

目前,我一直在ArgumentError in EventsController#create - Argument out of range。我认为这是因为数据库期望格式正确的日期时间对象。

关于如何实现我的目标的任何想法,在这里,不更改params,但仍然能够保存格式正确的对象?

2 个答案:

答案 0 :(得分:2)

我猜测问题发生在ActiveRecord提供的start= mutator方法中。如果你在控制器中做这样的事情:

@event.update_attributes(params[:events])
@event = Event.create(params[:event])
#...

然后createupdate_attributes应在内部调用start=。这应该允许您将慢性内容放入您自己的start=

def start=(t)
  super(Chronic.parse(t))
end

您可能需要针对非字符串t进行调整,例如,我不确定Chronic.parse(Time.now)会做什么。如果您不想向write_attribute(:start, Chronic.parse(t))投标,也可以致电self[:start] = Chronic.parse(t)super

请注意before_validation和类似的处理程序将被调用太晚,无法绕过ActiveRecord正在执行的默认字符串到时间戳的转换,但是mutator覆盖应该在正确的时间发生。

或者,您可以使用以下内容解析控制器中的时间:

event = params[:events].dup
events[:start] = Chronic.parse(events[:start])
@event = Event.create(event)

答案 1 :(得分:0)

假设是所有陷入困境的母亲:)

  • 你确定回调被击中了吗?因为如果它会,并且发生错误(就像它一样),它是否仍然会将不正确的数据(因为已解析)发送回视图?如有疑问:记录一些东西以确保它被击中。
  • 您确定哪个字段会导致Argument out of range错误。

大多数情况下很难找到/修复错误,因为我们假设我们知道错误,但我们正在以错误的方式查看错误。

测试哪个属性导致错误的简便方法:

  • 打开rails console,使用参数构建对象,保存并询问错误。像

    这样的东西

    e = Event.new(params [:event])#copy params from loglog from logfile e.save e.errors

,这将显示哪个字段导致错误。

或者:使用pry并在保存后添加一行binding.pry,以便检查errors(更多info

答案(假设你的假设是正确的)

我看到两个选项可以做你想做的事情:

  • 使用after_validation回调,如果您确定数据始终正确,并由Chronic正确解析。这样,如果验证通过,则转换字段,通常不会出现任何问题,并且该值永远不会再次发送到浏览器。

注意:如果某个其他属性导致错误,那么此回调永远不会被命中。因为它没有通过验证。

  • 使用虚拟属性,例如start_str,它是你开始的视觉表现,和 before_save将其转换为start。这里真的不重要,因为如果验证失败,您只需显示start_str而不是“真正的”start字段。