如何在Rails中覆盖to_json?

mač*_*ček 93 methods json overriding ruby-on-rails


更新:

这个问题没有得到适当的探索.真正的问题在于render :json.

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

render :json => current_user

一样的

render :json => current_user.to_json

也就是说,render :json不会自动调用to_json与User对象关联的方法.实际上,如果to_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
Run Code Online (Sandbox Code Playgroud)

这一切对我来说都很愚蠢.这似乎告诉我,在指定类型时render实际上并没有调用.谁能解释一下这里到底发生了什么?Model#to_json: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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

Jon*_*ian 208

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

def to_json(options)
  ...
end
Run Code Online (Sandbox Code Playgroud)

的更详细的解释to_json,as_json和渲染:

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

现在,随时to_json调用一个对象,as_json调用它来创建数据结构,然后使用该哈希编码为JSON字符串ActiveSupport::json.encode.所有类型都会发生这种情况:对象,数字,日期,字符串等(请参阅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
Run Code Online (Sandbox Code Playgroud)

在您的控制器中,render :json => o可以接受字符串或对象.如果它是一个字符串,它将作为响应体传递,如果它是一个对象,to_json则调用它as_json,如上所述触发.

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

format.json { render :json => @user }
Run Code Online (Sandbox Code Playgroud)

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

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

  • "def as_json(选项)"救了我的命.感谢宝贵的信息. (2认同)

Sam*_*fes 71

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

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

  • 希望我能给你多个投票:) (2认同)

Dan*_*npe 34

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

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

希望这有助于任何人:)


gle*_*ebm 5

不是覆盖 to_json,而是覆盖 as_json。从 as_json 调用你想要的:

尝试这个:

def as_json 
 { :username => username, :foo => foo, :bar => bar }
end
Run Code Online (Sandbox Code Playgroud)