Update:
This issue was not properly explored. The real issue lies within render :json
.
这个问题没有得到适当的探讨。真正的问题在于呈现:json。
The first code paste in the original question will yield the expected result. However, there is still a caveat. See this example:
原始问题中的第一个代码粘贴将产生预期的结果。然而,仍有一个警告。看这个例子:
render :json => current_user
呈现:json = > current_user
is NOT the same as
不一样吗
render :json => current_user.to_json
呈现:json = > current_user.to_json
That is, render :json
will not automatically call the to_json
method associated with the User object. In fact, if to_json
is being overridden on the User
model, render :json => @user
will generate the ArgumentError
described below.
也就是说,render:json不会自动调用与User对象关联的to_json方法。实际上,如果用户模型上覆盖了to_json,那么呈现:json => @user将生成下面描述的ArgumentError。
summary
# 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
This all seems silly to me. This seems to be telling me that render
is not actually calling Model#to_json
when type :json
is specified. Can someone explain what's really going on here?
这一切在我看来都是愚蠢的。这似乎在告诉我,当类型:json被指定时,渲染实际上并没有调用Model#to_json。有人能解释一下这里到底发生了什么吗?
Any genii that can help me with this can likely answer my other question: How to build a JSON response by combining @foo.to_json(options) and @bars.to_json(options) in Rails
任何能帮助我实现这一点的genii都可以回答我的另一个问题:如何通过在Rails中结合@foo.to_json(options)和@bars.to_json(options)来构建JSON响应
Original Question:
I've seen some other examples on SO, but I none do what I'm looking for.
我见过其他的例子,但是我没有做我想做的。
I'm trying:
我尝试:
class User < ActiveRecord::Base
# this actually works! (see update summary above)
def to_json
super(:only => :username, :methods => [:foo, :bar])
end
end
I'm getting ArgumentError: wrong number of arguments (1 for 0)
in
我得到了ArgumentError:错误的参数数(1代表0)
/usr/lib/ruby/gems/1.9.1/gems/activesupport-2.3.5/lib/active_support/json/encoders/object.rb:4:in `to_json
Any ideas?
什么好主意吗?
4 个解决方案
#1
203
You are getting ArgumentError: wrong number of arguments (1 for 0)
because to_json
needs to be overridden with one parameter, the options
hash.
您将得到ArgumentError:错误的参数数(1代表0),因为to_json需要使用一个参数,即options散列重写。
def to_json(options)
...
end
Longer explanation of to_json
, as_json
, and rendering:
to_json、as_json和呈现的更详细解释:
In ActiveSupport 2.3.3, as_json
was added to address issues like the one you have encountered. The creation of the json should be separate from the rendering of the json.
在ActiveSupport 2.3.3中,添加了as_json以解决您遇到的问题。json的创建应该与json的呈现分开。
Now, anytime to_json
is called on an object, as_json
is invoked to create the data structure, and then that hash is encoded as a JSON string using ActiveSupport::json.encode
. This happens for all types: object, numeric, date, string, etc (see the ActiveSupport code).
现在,无论何时调用对象to_json,都会调用as_json来创建数据结构,然后使用ActiveSupport:: JSON .encode将该散列编码为JSON字符串。这适用于所有类型:对象、数字、日期、字符串等(参见ActiveSupport代码)。
ActiveRecord objects behave the same way. There is a default as_json
implementation that creates a hash that includes all the model's attributes. You should override as_json
in your Model to create the JSON structure you want. as_json
, just like the old to_json
, takes an option hash where you can specify attributes and methods to include declaratively.
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
In your controller, render :json => o
can accept a string or an object. If it's a string, it's passed through as the response body, if it's an object, to_json
is called, which triggers as_json
as explained above.
在控制器中,render:json => o可以接受字符串或对象。如果它是一个字符串,它将作为响应主体传递,如果它是一个对象,则调用to_json,它将触发如上所述的as_json。
So, as long as your models are properly represented with as_json
overrides (or not), your controller code to display one model should look like this:
因此,只要您的模型用as_json重写(或不使用as_json重写)恰当地表示,那么显示一个模型的控制器代码应该如下所示:
format.json { render :json => @user }
The moral of the story is: Avoid calling to_json
directly, allow render
to do that for you. If you need to tweak the JSON output, call as_json
.
这个故事的寓意是:避免直接调用to_json,允许渲染为您这样做。如果需要调整JSON输出,请调用as_json。
format.json { render :json =>
@user.as_json(:only => [:username], :methods => [:avatar]) }
#2
70
If you're having issues with this in Rails 3, override serializable_hash
instead of as_json
. This will get your XML formatting for free too :)
如果您在Rails 3中遇到这个问题,请重写serizabalile_hash而不是as_json。这将使您的XML格式得到*:)
This took me forever to figure out. Hope that helps someone.
我花了很长时间才弄明白。希望可以帮助别人。
#3
30
For people who don't want to ignore users options but also add their's:
对于那些不想忽略用户选项,但也想添加自己的选项的人:
def as_json(options)
# this example DOES NOT ignore the user's options
super({:only => [:email, :handle]}.merge(options))
end
Hope this helps anyone :)
希望这对任何人都有帮助。
#4
3
Override not to_json, but as_json. And from as_json call what you want:
重写不是to_json,而是as_json。从as_json调用你想要的:
Try this:
试试这个:
def as_json
{ :username => username, :foo => foo, :bar => bar }
end
#1
203
You are getting ArgumentError: wrong number of arguments (1 for 0)
because to_json
needs to be overridden with one parameter, the options
hash.
您将得到ArgumentError:错误的参数数(1代表0),因为to_json需要使用一个参数,即options散列重写。
def to_json(options)
...
end
Longer explanation of to_json
, as_json
, and rendering:
to_json、as_json和呈现的更详细解释:
In ActiveSupport 2.3.3, as_json
was added to address issues like the one you have encountered. The creation of the json should be separate from the rendering of the json.
在ActiveSupport 2.3.3中,添加了as_json以解决您遇到的问题。json的创建应该与json的呈现分开。
Now, anytime to_json
is called on an object, as_json
is invoked to create the data structure, and then that hash is encoded as a JSON string using ActiveSupport::json.encode
. This happens for all types: object, numeric, date, string, etc (see the ActiveSupport code).
现在,无论何时调用对象to_json,都会调用as_json来创建数据结构,然后使用ActiveSupport:: JSON .encode将该散列编码为JSON字符串。这适用于所有类型:对象、数字、日期、字符串等(参见ActiveSupport代码)。
ActiveRecord objects behave the same way. There is a default as_json
implementation that creates a hash that includes all the model's attributes. You should override as_json
in your Model to create the JSON structure you want. as_json
, just like the old to_json
, takes an option hash where you can specify attributes and methods to include declaratively.
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
In your controller, render :json => o
can accept a string or an object. If it's a string, it's passed through as the response body, if it's an object, to_json
is called, which triggers as_json
as explained above.
在控制器中,render:json => o可以接受字符串或对象。如果它是一个字符串,它将作为响应主体传递,如果它是一个对象,则调用to_json,它将触发如上所述的as_json。
So, as long as your models are properly represented with as_json
overrides (or not), your controller code to display one model should look like this:
因此,只要您的模型用as_json重写(或不使用as_json重写)恰当地表示,那么显示一个模型的控制器代码应该如下所示:
format.json { render :json => @user }
The moral of the story is: Avoid calling to_json
directly, allow render
to do that for you. If you need to tweak the JSON output, call as_json
.
这个故事的寓意是:避免直接调用to_json,允许渲染为您这样做。如果需要调整JSON输出,请调用as_json。
format.json { render :json =>
@user.as_json(:only => [:username], :methods => [:avatar]) }
#2
70
If you're having issues with this in Rails 3, override serializable_hash
instead of as_json
. This will get your XML formatting for free too :)
如果您在Rails 3中遇到这个问题,请重写serizabalile_hash而不是as_json。这将使您的XML格式得到*:)
This took me forever to figure out. Hope that helps someone.
我花了很长时间才弄明白。希望可以帮助别人。
#3
30
For people who don't want to ignore users options but also add their's:
对于那些不想忽略用户选项,但也想添加自己的选项的人:
def as_json(options)
# this example DOES NOT ignore the user's options
super({:only => [:email, :handle]}.merge(options))
end
Hope this helps anyone :)
希望这对任何人都有帮助。
#4
3
Override not to_json, but as_json. And from as_json call what you want:
重写不是to_json,而是as_json。从as_json调用你想要的:
Try this:
试试这个:
def as_json
{ :username => username, :foo => foo, :bar => bar }
end