Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 处理混合数—;在模型中?_Ruby On Rails_Ruby - Fatal编程技术网

Ruby on rails 处理混合数—;在模型中?

Ruby on rails 处理混合数—;在模型中?,ruby-on-rails,ruby,Ruby On Rails,Ruby,我有一个包含大量字段的表单,这些字段以小数形式存储在数据库中 但是,我希望用户能够输入分数,特别是混合数(例如38 1/2) 为将混合数转换为分数提供了一个很好的解决方案,我对其进行了修改,并将其放入模型中的函数中: def to_dec self.chest = self.chest.split.map { |r| Rational(r) }.inject(:+).to_f end 我已经尝试过在保存之前用validate:to_dec和调用它。然而,这两种方法都不起作用 我知道为什么,

我有一个包含大量字段的表单,这些字段以小数形式存储在数据库中

但是,我希望用户能够输入分数,特别是混合数(例如38 1/2)

为将混合数转换为分数提供了一个很好的解决方案,我对其进行了修改,并将其放入模型中的函数中:

def to_dec
  self.chest = self.chest.split.map { |r| Rational(r) }.inject(:+).to_f
end
我已经尝试过在保存之前用
validate:to_dec
调用它。然而,这两种方法都不起作用

我知道为什么,但不知道如何修复它

通过使用
put self.chest
我能够在我有机会调整之前判断出该值正在转换为一个数字。在我的表单中输入'10 1/2'并保存,
放入self.cost
将为我提供10.0,即使该函数只是:

def to_dec
  puts self.chest
end
另外,
将'38 1/2'。split.map{r | Rational(r)}.inject(:+).to|d
给我38.5,所以我知道问题不在转换中

我已经将视图输入类型从数字改为字符串,但我的模型中似乎仍然有一个数字

我卡住了


另外,其他一些字段也需要支持混合数——我想以某种方式将其抽象出来,这样就不需要为每个值编写不同的函数

原因是ActiveRecord在定义模型属性时会查看数据库模式。这就是所有属性在模型类上的显示方式,而无需像在普通的旧Ruby对象上一样,使用
attr\u访问器:cost
(或
def-cost
def-cost=
)手动定义它们

执行此操作时,ActiveRecord还会查看列类型,并在分配属性时应用类型转换。因此,因为您的
cost
列是十进制的,所以它将您提供给它的任何字符串转换为浮点。在这样做时,它将获取可以转换的字符串的第一位,并丢弃其余的,这就是为什么会得到
38.0

您可以通过两种方式来解决这个问题—您可以将数字作为字符串存储在数据库中,这可能会节省一些转换(但如果需要在查询中使用数字表示,则不会太有用),也可以使用字符串

基本上,您需要定义一个getter和setter,如下所示:

def rational_chest
  # I assume this would create a rational from a float
  # and respond to `to_s` in a sane manner...
  Rational(chest) if chest
end

def rational_chest=(value)
  self.chest = parse_rational(value)
end

private

def parse_rational(value)
  return nil if value.blank?
  value.split.map{|r| Rational(r)}.inject(:+).to_f
end
然后在你的表单中使用
rational\u-cost
,而不仅仅是
cost

由于您需要在多个字段上执行此操作,因此可以求助于一些漂亮的元编程:

def self.rational_attribute(attribute)
  define_method("rational_#{attribute}") do
    Rational(send(attribute))
  end

  define_method("rational_#{attribute}=") do |value|
    send "#{attribute}=", value.split.map{|r| Rational(r)}.inject(:+).to_f
  end
end

def self.rational_attributes(*attributes)
  attributes.each {|attribute| rational_attribute attribute}
end

rational_attributes :chest, :waist, :etc

如果你在多个模型中使用它,把它放在一个模块中(没有
self.
s和
extend
it!

我用
If-cost
编辑了你的答案,因为如果留空它会抛出一个错误。这非常有用而且解释得很好!一个缺点是它允许不正确的分数(77/2,等等)但这很容易通过删除
Rational()来解决
。它给出了一个小数。最终我可以使用它将其转换回一个混合数。感谢您的帮助!嗯…我能够解决第一个示例中留下空白值的问题,但我正在努力解决第二个示例。我希望允许空白输入。有什么想法吗?我将此错误
未定义方法
发送给您l:NilClass`Ah yep good call,我没有考虑过这种情况。我可能会将解析拆分为一个单独的方法,如我最近的编辑所示。总体而言,听起来您的需求比您拥有的基本
Rational
类稍微复杂一些,也许值得考虑开发一个自定义
度量
class。另外,
cost\u was
应该在rails将其转换为数据库中为该属性定义的类型之前为您提供值。当我创建新记录时,我再次收到一些关于nil的错误,但是如果我从
send(attribute)
中删除
Rational()
,它就会消失。不过,对于我的用例来说,这不是问题。。。