【问题标题】:Rails 3: using composed_of with validation causes ActiveRecord errorRails 3:使用committed_of进行验证会导致ActiveRecord错误
【发布时间】:2012-02-05 01:31:22
【问题描述】:

我正在使用以下code snippet from the Rails docs 将 IP 转换为整数,然后再将它们插入数据库:

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 不相符。这是否正确,如果正确,是否有解决办法?

【问题讨论】:

  • 你是对的,但不幸的是我没有适合你的解决方案。自从我写的一个 gem 有同样的问题以来,我一直在尝试解决这个问题。
  • 解决方案并不简单。我认为这涉及重新打开 IPAddr 并添加include ActiveRecord::Validations,但除此之外还有很多。一旦你这样做了,你还必须添加一堆 Rails 期望 ActiveRecord::Base 类拥有的方法,我认为你必须覆盖唯一性验证器的某些部分。如果我有时间,我可能会尝试解决这个问题并在明天提供答案,但我无法做出任何承诺。也许这足以帮助您取得一些进步。
  • @Ryan 你有没有想过解决这个问题?你发布了一些想法,我很好奇你是否有任何想法。
  • @Beerlington 不幸的是,我并没有走得太远。我仍然认为我在正确的轨道上,但没有能够投入足够的时间。

标签: ruby-on-rails ruby-on-rails-3 validation activerecord ip-address


【解决方案1】:

不确定您是否找到了解决方案,但我可以通过向 Arel 添加访问方法在我的 gem 中对其进行修补。

您应该能够执行以下操作以使其正常工作。这基于 Arel converts values 对日期等其他类型的对象的方式。不确定是否需要将值转换为字符串,但它可能只是作为整数工作。

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

我需要能够动态生成这些方法,所以我在我的 gem 中使用了以下内容:

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

【讨论】:

  • 感谢分享。我从不费心寻找解决方案,但如果我今天要尝试,我会放弃 IPAddr 并尝试使用注入方法转换 IP(无论如何工作速度更快)
  • visit_IPAddr 的签名取决于您需要支持的 Arel 版本。在 Arel 4.0.2(在 Rails 4.0 中使用)中,它应该是 visit_IPAddr(object, attribute),而在最新版本中它应该是 visit_IPAddr(object)。无论哪种情况,在方法中使用给定的object 而不是value
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-04
  • 2013-12-25
  • 1970-01-01
  • 2011-06-01
相关资源
最近更新 更多