从其json表示

时间:2016-04-10 00:52:39

标签: ruby-on-rails ruby json postgresql devise

如何从json表示中获取IPAddr实例?

上下文:

我正在使用一个使用draftsman gem的Rails应用程序。基本上,当一个人对数据库中的记录和ruby模型has_drafts进行更改时,不会立即对记录进行更改,而是将更改草稿和结果记录保存在草稿表中,直到一个publish! es草案。然后对实际记录进行更改。非常整洁:)

草稿表保存了允许更改在postgres表中的json列中发生的对象。

我也在使用Devise,我的用户模型使用trackable模块,其中包含current_sign_in_ip以及last_sign_in_ip列类型inet

问题:

我的用户表中的

inet类型列以及User对象的其余部分存储在由单个json列中的draftsman gem创建的草稿表中叫object。由于以下原因,reify草案中的对象在这种情况下不会成功:IPAddr个实例具有IPAddr类无法感知的json表示。例如,ruby中的IPAddr个实例会回复to_json,这会给我一些如下所示的内容:"\"family\":2,\"addr\":2130706433,\"mask_addr\":4294967295}"。这些实例也会回复to_s并给我这样的内容:"127.0.0.1"。不幸的是,IPAddr类似乎不知道如何从我所知道的json中恢复过来:

[277, 286] in /home/jake/.rvm/gems/ruby-2.2.1/bundler/gems/draftsman-1bd3c797d540/lib/draftsman/model.rb
   277:               data = {
   278:                 :item      => self,
   279:                 :whodunnit => Draftsman.whodunnit,
   280:                 :object    => object_attrs_for_draft_record
   281:               }
=> 282:               data = merge_metadata_for_draft(data)
   283: 
   284:               # If there's already a draft, update it.
   285:               if send(self.class.draft_association_name).present?
   286:                 data[:object_changes] = changes_for_draftsman if track_object_changes_for_draft?

(byebug) data[:object]['current_sign_in_ip']
#<IPAddr: IPv4:127.0.0.1/255.255.255.255>
(byebug) data[:object]['current_sign_in_ip'].to_json
"{\"family\":2,\"addr\":2130706433,\"mask_addr\":4294967295}"

(byebug) IPAddr.new(data[:object]['current_sign_in_ip'].to_s)
#<IPAddr: IPv4:127.0.0.1/255.255.255.255>
(byebug) IPAddr.new(data[:object]['current_sign_in_ip'].to_json)
*** IPAddr::InvalidAddressError Exception: invalid address

nil
(byebug) 

我认为将这个问题发布到StackOverflow会引起一些关注,但如果需要任何其他信息,我还会在Draftsman github页面上提交一个github issue

3 个答案:

答案 0 :(得分:2)

不确定这是否有帮助,但如果您在d_ethier的回答下面阅读我的评论,您会发现IPAddr对JSON一无所知。

但是你可以修补它来理解JSON,如下所示:

require 'active_model'
require 'active_support'
require 'active_support/core_ext'
require 'ipaddr'

class IPAddr
  include ActiveModel::Serializers::JSON

  attr_accessor :addr, :mask_addr, :family

  def attributes=(hash)
    hash.each do |key, value|
      send("#{key}=", value)
    end
  end

  def attributes
    instance_values
  end
end   

p i = IPAddr.new('127.0.0.1')
p j = i.to_json
p IPAddr.new.from_json(j)

输出:

#<IPAddr: IPv4:127.0.0.1/255.255.255.255>
"{\"family\":2,\"addr\":2130706433,\"mask_addr\":4294967295}"
#<IPAddr: IPv4:127.0.0.1/255.255.255.255>

来源:
http://apidock.com/rails/ActiveModel/Serializers/JSON/from_json

答案 1 :(得分:0)

我怀疑这个问题是另一回事。

import net.glxn.qrgen.QRCode; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; public static BufferedImage generate() { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); QRCode.from("http://www.stackoverflow.com").writeTo(baos); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); return ImageIO.read(bais); } catch (Exception e) { e.printStackTrace(); } return null; } 并未改变IPAddr.new(data[:object]['current_sign_in_ip'].to_s)的内容,因此不应该成为&#34;转换&#34;的理由。它回来了。

实际上,data[:object]['current_sign_in_ip']已经是IPAddr对象。在IPAddr.new中包装它是多余的。

我怀疑您正在尝试做其他事情而这只是您的描述,所以如果没有看到您的代码,就很难提供帮助。

如果是这种情况,您可以通过为原始IPAddr实例创建变量并稍后使用它来解决此问题。

data[:object]['current_sign_in_ip']

答案 2 :(得分:0)

如果有人看到这个,我们在 ActiveSupport 中修复了这个问题

https://github.com/rails/rails/issues/40932 https://github.com/rails/rails/commit/e7d207f02fe8bf6e351de7da106839b0ab14bbea

如果使用 Rails,我们应该可以使用初始化程序来解决这个问题:

class IPAddr
  def as_json(options = nil)
    to_s
  end
end