Ruby-on-rails 如何在 Rails 中覆盖 to_json?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2572284/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 22:29:58  来源:igfitidea点击:

How to override to_json in Rails?

ruby-on-railsjsonmethodsoverriding

提问by ma?ek



Update:

更新:

This issue was not properly explored. The real issue lies within render :json.

这个问题没有得到适当的探讨。真正的问题在于render :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

render :json => current_user

is NOTthe same as

一样的

render :json => current_user.to_json

render :json => current_user.to_json

That is, render :jsonwill not automatically call the to_jsonmethod associated with the User object. In fact, if to_jsonis being overridden on the Usermodel, render :json => @userwill generate the ArgumentErrordescribed below.

也就是说,render :json不会自动调用to_json与 User 对象关联的方法。事实上,如果to_jsonUser模型上被覆盖,render :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 renderis not actually calling Model#to_jsonwhen type :jsonis specified. Can someone explain what's really going on here?

这一切在我看来都很愚蠢。这似乎告诉我在指定类型时render实际上并没有调用。有人可以解释这里到底发生了什么吗?Model#to_json: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

任何可以帮助我解决这个问题的精灵都可能回答我的另一个问题:如何通过在 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.

我在 SO 上看到了其他一些例子,但我没有做我正在寻找的。

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: 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

Any ideas?

有任何想法吗?

回答by Jonathan Julian

You are getting ArgumentError: wrong number of arguments (1 for 0)because to_jsonneeds to be overridden with one parameter, the optionshash.

你得到的ArgumentError: wrong number of arguments (1 for 0)是因为to_json需要用一个参数覆盖,options哈希。

def to_json(options)
  ...
end


Longer explanation of to_json, as_json, and rendering:

的更详细的解释to_jsonas_json和渲染:

In ActiveSupport 2.3.3, as_jsonwas added to address issues like the one you have encountered. The creationof the json should be separate from the renderingof the json.

在 ActiveSupport 2.3.3 中,as_json添加了用于解决您遇到的类似问题。json的创建应该与json的渲染分开。

Now, anytime to_jsonis called on an object, as_jsonis 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. 这适用于所有类型:对象、数字、日期、字符串等(请参阅 ActiveSupport 代码)。

ActiveRecord objects behave the same way. There is a default as_jsonimplementation that creates a hash that includes all the model's attributes. You should override as_jsonin 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 => ocan 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_jsonis called, which triggers as_jsonas explained above.

在你的控制器中,render :json => o可以接受一个字符串或一个对象。如果它是一个字符串,它会作为响应体传递,如果它是一个对象,to_json则被调用,它会as_json按照上面的解释触发。

So, as long as your models are properly represented with as_jsonoverrides (or not), your controller code to display one model should look like this:

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

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

The moral of the story is: Avoid calling to_jsondirectly, allow renderto do that for you. If you need to tweak the JSON output, call as_json.

这个故事的寓意是:避免to_json直接打电话,允许render为你这样做。如果您需要调整 JSON 输出,请调用as_json.

format.json { render :json => 
    @user.as_json(:only => [:username], :methods => [:avatar]) }

回答by Sam Soffes

If you're having issues with this in Rails 3, override serializable_hashinstead of as_json. This will get your XML formatting for free too :)

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

This took me forever to figure out. Hope that helps someone.

这让我花了很长时间才弄明白。希望能帮助某人。

回答by Danpe

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 :)

希望这可以帮助任何人:)

回答by glebm

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