as_json的不同行为

时间:2014-05-22 17:16:22

标签: ruby-on-rails ruby-on-rails-3 rspec rspec2 rspec-rails

目前我对as_json方法有不同的行为。这就是我的规格无法成功运行的原因。

User.first.as_json
# => {"username"=>"Joe", "created_at"=>Thu, 24 Apr 2014 09:41:17 UTC +00:00 }

User.first.created_at.as_json
# => "2014-04-24T09:41:17Z"

在我的模型中,我添加了一个serializable_hash方法来限制json和xml中的字段:

def serializable_hash(options={})
  super(only: [:username, :created_at])
end

我的rspec行为测试以下内容会导致错误:

it "response in json format" do
  expect(json).to eq assigns[:user].as_json
end

错误仅提及两个时间戳不相等:

-"created_at" => Thu, 24 Apr 2014 09:41:17 UTC +00:00,
+"created_at" => "2014-04-24T09:41:17Z",

如何在第一行中设置成员对象的日期时间格式?

感谢您的帮助。

斯特芬

1 个答案:

答案 0 :(得分:0)

这种情况正在发生,因为它们是不同的序列化程序,具体取决于对象的类型是从as_json调用。

时间 as_json正在调用xmlschema,这将返回如下格式:%Y-%m-%dT%H:%M:%S Z请按照此处的源代码(使用PRY):

pry(main)> show-source User.first.validated_at.as_json
def as_json(options = nil)
  if ActiveSupport::JSON::Encoding.use_standard_json_time_format
    xmlschema
  else
    %(#{time.strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
  end
end

pry(main)> show-source User.first.validated_at.xmlschema
def xmlschema(fraction_digits = 0)
  fraction = if fraction_digits > 0
    (".%06i" % time.usec)[0, fraction_digits + 1]
  end

  "#{time.strftime("%Y-%m-%dT%H:%M:%S")}#{fraction}#{formatted_offset(true, 'Z')}"
end

ActiveRecord as_json正在调用serializable_hash,而且每个字段最终都会返回to_s,返回这种格式:%Y-% m-%d%H:%M:%S UTC

pry(main)> show-source User.first.as_json
def as_json(options = nil)
  root = include_root_in_json
  root = options[:root] if options.try(:key?, :root)
  if root
    root = self.class.model_name.element if root == true
    { root => serializable_hash(options) }
  else
    serializable_hash(options)
  end
end

pry(main)> show-source User.first.serializable_hash
def serializable_hash(options = nil)
  options = options.try(:clone) || {}

  options[:except] = Array.wrap(options[:except]).map { |n| n.to_s }
  options[:except] |= Array.wrap(self.class.inheritance_column)

  super(options)
end

pry(main)> show-source User.first.validated_at.to_s
def to_s(format = :default)
  if format == :db
    utc.to_s(format)
  elsif formatter = ::Time::DATE_FORMATS[format]
    formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
  else
    "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby 1.9 Time#to_s format
  end
end