3

我使用以下code snippet from the Rails docs将它们插入到数据库之前,IP地址到整数转换:的Rails 3:使用composed_of与验证导致ActiveRecord的错误

composed_of :user_ip, 
      :class_name => 'IPAddr', 
      :mapping => %w(user_ip to_i), 
      :constructor => Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) }, 
      :converter => Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) } 

的composed_of块随后是这种简单的验证:

validates_uniqueness_of :user_ip 

但反过来验证抛出试图创建一个新的对象时出现错误:

TypeError: Cannot visit IPAddr 

删除验证,错误消失。

如果我理解正确,就会发生这种情况,因为:user_ip变为IPAddr对象,并且ActiveRecord不适合。这是否正确,如果有,是否有解决方法?

+0

你是正确的,但不幸的是,我没有你的解决方案。自从我写的宝石出现同样的问题以来,我一直试图找出这个问题。 – 2012-02-05 04:00:28

+0

解决方案并不简单。我认为它涉及到重新打开IPAddr并添加“include ActiveRecord :: Validations”,但还有很多不足之处。一旦你这样做了,你还必须添加一些方法,Rails希望ActiveRecord :: Base类具有,我认为你必须重写唯一性验证器的某些部分。如果我有时间,我可能会尝试解决这个问题,并在明天提供答案,但我不能做出任何承诺。也许这足以帮助你取得一些进展。 – Ryan 2012-02-05 07:58:32

+0

@Ryan你有没有想过解决这个问题?你发布了一些想法,我很好奇,如果你有它的任何地方。 – 2012-04-24 01:45:37

回答

2

不知道您是否曾经找到过解决方案,但是我可以通过向Arel添加访问方法将其修补到我的宝石中。

你应该可以做下面的事情来实现它。这是根据Arel converts values如何用于其他类型的对象如日期。不知道你是否需要将该值转换为字符串,但它可能只是一个整数。

module Arel 
    module Visitors 
    class ToSql 
     def visit_IPAddr 
     quote(value.to_i) 
     end 
    end 
    end 
end 

我需要能够动态生成这些方法,所以我用我的宝石如下:

Arel::Visitors::ToSql.class_eval do 
    define_method "visit_#{klass.name}", lambda {|value| quote(value.to_s) } 
end 
+0

感谢分享。我从来没有打算找到解决方案,但如果我今天要尝试,我会放弃IPAddr,并尝试使用注入方法转换IP(无论如何,它的工作更快) – Marco 2012-04-29 23:17:48

+0

“visit_IPAddr”的签名取决于您需要支持的Arel版本。在Arel 4.0.2(在Rails 4.0中使用)中,它应该是'visit_IPAddr(object,attribute)',最迟应该是'visit_IPAddr(object)'。无论哪种情况,在方法中使用给定的'object'而不是'value'。 – Brandan 2014-12-19 19:39:24

相关问题