json - 如何在Rails中覆盖to_json?


更新:

这个问题没有得到适当的探索。 真正的问题在于ArgumentError: wrong number of arguments (1 for 0)

原始问题中的第一个代码粘贴将产生预期结果。 但是,仍然有一个警告。 看这个例子:

ArgumentError: wrong number of arguments (1 for 0)

是不一样的

ArgumentError: wrong number of arguments (1 for 0)

也就是说,ArgumentError: wrong number of arguments (1 for 0)不会自动调用与User对象关联的Model#to_json方法。 实际上,如果:jsonUser型号上被覆盖,则render :json => @user将生成下面描述的ArgumentError

摘要

# works if User#to_json is not overridden
render :json => current_user

# If User#to_json is overridden, User requires explicit call
render :json => current_user.to_json

这一切对我来说都很愚蠢。 这似乎告诉我,当指定类型:json时,ArgumentError: wrong number of arguments (1 for 0)实际上并未调用Model#to_json。 有人能解释一下这里真正发生了什么吗?

任何可以帮助我的genii都可以回答我的另一个问题:如何通过在Rails中组合@ foo.to_json(options)和@ bars.to_json(options)来构建JSON响应


原始问题:

我在SO上看过其他一些例子,但我没有做我想要的事情。

我正在尝试:

class User < ActiveRecord::Base

  # this actually works! (see update summary above)
  def to_json
    super(:only => :username, :methods => [:foo, :bar])
  end

end

我来的是ArgumentError: wrong number of arguments (1 for 0)

/usr/lib/ruby/gems/1.9.1/gems/activesupport-2.3.5/lib/active_support/json/encoders/object.rb:4:in `to_json

有任何想法吗?

maček asked 2019-08-11T20:29:25Z
4个解决方案
208 votes

您将获得to_json因为render需要使用一个参数as_json哈希重写。

def to_json(options)
  ...
end

更长的解释to_json,render和渲染:

在ActiveSupport 2.3.3中,添加了to_json以解决您遇到的问题。 json的创建应该与json的渲染分开。

现在,在对象上调用to_json时,会调用render来创建数据结构,然后使用as_json将该哈希编码为JSON字符串。这种情况适用于所有类型:对象,数字,日期,字符串等(请参阅 ActiveSupport代码)。

ActiveRecord对象的行为方式相同。 有一个默认的to_json实现,它创建一个包含所有模型属性的哈希。 您应该在模型中覆盖to_json以创建所需的JSON结构。 render,就像旧的as_json一样,采用一个选项哈希,您可以在其中指定要以声明方式包含的属性和方法。

def as_json(options)
  # this example ignores the user's options
  super(:only => [:email, :handle])
end

在控制器中,to_json可以接受字符串或对象。 如果它是一个字符串,它将作为响应主体传递,如果它是一个对象,则调用to_json,如上所述触发render

因此,只要您的模型用to_json覆盖(或不覆盖)正确表示,显示一个模型的控制器代码应如下所示:

format.json { render :json => @user }

故事的寓意是:避免直接致电to_json,允许render为您做到这一点。 如果需要调整JSON输出,请致电as_json

format.json { render :json => 
    @user.as_json(:only => [:username], :methods => [:avatar]) }
Jonathan Julian answered 2019-08-11T20:30:30Z
71 votes

如果您在Rails 3中遇到此问题,请覆盖serializable_hash而不是as_json.这也将免费获取您的XML格式:)

这让我永远想通了。 希望能帮助别人。

Sam Soffes answered 2019-08-11T20:31:03Z
32 votes

对于那些不想忽略用户选项但又添加他们的用户的人:

def as_json(options)
  # this example DOES NOT ignore the user's options
  super({:only => [:email, :handle]}.merge(options))
end

希望这有助于任何人:)

Danpe answered 2019-08-11T20:31:37Z
3 votes

覆盖不是to_json,而是as_json。从as_json打电话给你想要的:

试试这个:

def as_json 
 { :username => username, :foo => foo, :bar => bar }
end
glebm answered 2019-08-11T20:32:05Z
translate from https://stackoverflow.com:/questions/2572284/how-to-override-to-json-in-rails