此问题未得到适当探讨。真正的问题在于render :json
。
原始问题中的第一个代码粘贴将产生预期结果。但是,仍然有一个警告。见这个例子:
render :json => current_user
不与
相同 render :json => current_user.to_json
也就是说,render :json
不会自动调用与User对象关联的to_json
方法。 实际上,如果在to_json
模型上覆盖User
,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
这一切对我来说都很愚蠢。这似乎告诉我,render
在指定类型Model#to_json
时实际上并未调用:json
。有人能解释一下这里到底发生了什么吗?
任何可以帮助我解决这个问题的genii都可能回答我的另一个问题:How to build a JSON response by combining @foo.to_json(options) and @bars.to_json(options) in Rails
我在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
有什么想法吗?
答案 0 :(得分:208)
您收到ArgumentError: wrong number of arguments (1 for 0)
因为to_json
需要使用一个参数options
哈希重写。
def to_json(options)
...
end
对to_json
,as_json
和呈现的更长解释:
在ActiveSupport 2.3.3中,添加了as_json
来解决您遇到的问题。 json的 creation 应该与json的呈现分开。
现在,无论何时在对象上调用to_json
,都会调用as_json
来创建数据结构,然后使用ActiveSupport::json.encode
将该哈希编码为JSON字符串。所有类型都会发生这种情况:对象,数字,日期,字符串等(请参阅ActiveSupport代码)。
ActiveRecord对象的行为方式相同。有一个默认的as_json
实现,它创建一个包含所有模型属性的哈希。 您应该在模型中覆盖as_json
以创建所需的JSON结构。 as_json
就像旧的to_json
一样,采用一个选项哈希,您可以在其中指定要以声明方式包含的属性和方法。
def as_json(options)
# this example ignores the user's options
super(:only => [:email, :handle])
end
在您的控制器中,render :json => o
可以接受字符串或对象。 如果它是一个字符串,它将作为响应主体传递,如果它是一个对象,则调用to_json
,如上所述触发as_json
。
因此,只要您的模型使用as_json
覆盖(或不覆盖)正确表示,显示一个模型的控制器代码应如下所示:
format.json { render :json => @user }
故事的寓意是:避免直接致电to_json
,允许render
为你做这件事。如果您需要调整JSON输出,请致电as_json
。
format.json { render :json =>
@user.as_json(:only => [:username], :methods => [:avatar]) }
答案 1 :(得分:71)
如果您在Rails 3中遇到此问题,请覆盖serializable_hash
而不是as_json
。这也将免费获得您的XML格式:)
这让我永远想通了。希望有所帮助。
答案 2 :(得分:32)
对于那些不想忽略用户选项但又添加他们的选项的人:
def as_json(options)
# this example DOES NOT ignore the user's options
super({:only => [:email, :handle]}.merge(options))
end
希望这有助于任何人:)
答案 3 :(得分:3)
覆盖不是to_json,而是as_json。 从as_json打电话给你想要的东西:
试试这个:
def as_json
{ :username => username, :foo => foo, :bar => bar }
end