ruby-on-rails 对ActiveRecord对象执行to_json操作ruby 3.0

zi8p0yeb  于 2023-02-14  发布在  Ruby
关注(0)|答案(3)|浏览(135)

我使用的是rails6.0.3.6和ruby 3.0.0,
当我调用{'user' : User.first }.to_json时,得到的是"{\"user\":\"#<User:0x00007fa0a8dae3c8>\"}"
[User.first, User.last].to_json相同
如果我切换回ruby 2.7.2,我会得到正确的结果,即<User:0x00007fa0a8dae3c8>替换为它的所有属性。
你知道我错过了什么吗

bgibtngc

bgibtngc1#

问题出在Rails www.example.com中6.0.3.6当在{'user' : User.first }上调用to_json时,Rails最终为to_json添加了JSON::Ext::Generator::State参数,因此options.is_a?(::JSON::State)返回true,并返回super(options)
根据to_json的定义:

def to_json(options = nil)
  if options.is_a?(::JSON::State)
    # Called from JSON.{generate,dump}, forward it to JSON gem's to_json
    super(options)
  else
    # to_json is being invoked directly, use ActiveSupport's encoder
    ActiveSupport::JSON.encode(self, options)
  end
end

而在最近的Rails中,to_json是在没有任何参数的情况下调用的,分支采用路径最终返回ActiveSupport::JSON.encode(self, options)
所以,在你的情况下,你可以

{ 'user': User.first.attributes }.to_json

为了“绕过”这个问题。

6ju8rftf

6ju8rftf2#

{'user': User.first }.as_json

使用as_json代替to_json

xe55xuns

xe55xuns3#

    • 设法在以下位置一致地复制此内容:**
  • Rails网站6.0.3.5
  • Ruby3.0.5
    • 有趣的事实:***Ruby 2.7.7-修复了这个问题 . * 升级到Rails 6.1 + 也是如此。所以严格地说,这是一组版本。
  • 尝试接触https://rubygems.org/gems/json版本。不影响
  • 尝试接触https://rubygems.org/gems/jbuilder版本。不影响

我们直接谈正事吧。
要始终重现并了解您遇到的问题,请打开Rails控制台并测试以下代码:

[User.first, User.last].to_json
=>
"[\"#<User:0x00007fbb497fad30>\",\"#<User:0x00007fbb5001df20>\"]"

{ test: User.limit(2).to_json }.to_json
=>
"{\"test\":\"#<User::ActiveRecord_Relation:0x00007fc0228b7d08>\"}"

如果你看到这样的输出-不幸的是你有这个问题,但这不是一个悲剧;)

    • 我在现场测试条件下遇到的问题,有人会发现这些问题是他们项目的典型问题,对重现/调试/测试过程很有用:**
  • 如果您有任何使用render json: { user: user }语法的API端点
  • jbuilder视图,使用下一个定义json.(@user, :id, :profile)或一些非序列化ActiveRecord对象,例如json.profile @user.profile
  • 所有场景,当您尝试显式转换为可枚举类中的任何对象时(您可以grep搜索所有. to_json用法)
payload = [
  <ActionController::Parameters {"user"=>{"profile"=>1}} permitted: false>
  1,
  2
].to_json
JSON.parse(payload)
=>
[
  String (instead of Hash),
  1,
  2
]
    • 解决方案:**
# config/initializers/monkey_patches.rb

# TODO: Remove after upgrade to Rails 6.1+. JSON serialization of Objects works fine there
# Source: https://stackoverflow.com/questions/66871265/to-json-on-activerecord-object-ruby-3-0
module ActiveSupport
  module FixBrokenJsonSerialization
    def to_json(options = nil)
      return ::ActiveSupport::JSON.encode(self) if options.is_a?(::JSON::Ext::Generator::State)

      super(options)
    end
  end
end

Object.prepend(ActiveSupport::FixBrokenJsonSerialization)
    • NB.**这不是一个万能的解决方案,而是一个猴子补丁,总是有风险和不好的。更好的解决方案是迁移到Rails 6.1或降级到Ruby 2.7.7(最后一个实际上非常烦人)。

如果您确实需要这些版本-* 请确保您没有任何具有大量JSON逻辑或以任何方式依赖于 * JSON::Ext::Generator::State的库。
除了这个事实-应该有助于保持它游泳👍

相关问题