首页 > 解决方案 > 在保存模型之前从视图中更改用户输入

问题描述

我有一个接受小数的模型(SQLite3 开发数据库)。但是,我希望用户输入一个字符串,例如“1:15:15”(可以人工读取为 1 小时 15 分 15 秒,或者 75 分 15 秒)。在我的模型中,我有一个 before_save 调用自定义私有方法将字符串转换为数字(请注意,是否使用私有具有相同的结果):

class LogEntry < ApplicationRecord
  belongs_to :user
  default_scope -> { order(date: :desc) }
  before_save :convert_runtime

  def convert_runtime
    a = self.runtime.split(':')
    #debugger
    self[:runtime] = a[0].to_f * 3600 + a[1].to_f * 60 + a[2].to_f 
  end
end

拆分给了我一个错误,所以当我插入debugger代码并将带有拆分的行更改为 only a = self.runtime(查看这个值实际上是什么)时,调试器会0.1e1为“a”变量生成一个值(a 用于数组)。因此,Rails 所做的似乎是将来自用户的字符串中的第一个值(“:”之前)转换为小数,忽略字符串的其余部分,然后再保存。有没有办法在整个字符串从视图传递到模型时对其进行操作,而不需要 Rails 首先将其转换为十进制形式?我的下一个选择是更改数据库以保存字符串。我觉得这不太理想,因为如果我想将多年的条目相加,每个字符串都需要先转换为数字,所以我宁愿将时间值存储为秒,并在输入时进行转换。

我已经坚持了一段时间了。

标签: ruby-on-rails

解决方案


您可以为您的字符串表示使用瞬态访问器,以便 activerecord 的键入助手不会转换您的值。像这样的东西:

class LogEntry < ApplicationRecord
  belongs_to :user
  default_scope -> { order(date: :desc) }

  attr_accessor :runtime_string

  before_save :convert_runtime

  def convert_runtime
    a = runtime_string.split(':')
    #debugger
    self[:runtime] = a[0].to_f * 3600 + a[1].to_f * 60 + a[2].to_f 
  end
end

自然,您的表单必须runtime_string立即使用

<%= f.text_field :runtime_string %>

推荐阅读