Ruby on Rails 高级 JSON 序列化

Posted

技术标签:

【中文标题】Ruby on Rails 高级 JSON 序列化【英文标题】:Ruby on Rails Advanced JSON Serialization 【发布时间】:2010-10-11 02:36:00 【问题描述】:

我希望在我的 rails 应用程序中通过 JSON 呈现所有文章的索引以及完整文章,但我在弄清楚如何做到这一点时遇到了一些麻烦。

这是我的控制器:

if params[:id]
    @article = Article.find(params[:id])
else
    @article = Article.published.not_draft.by_recent.first
end

respond_to do |format|

format.js  render :json => @article.to_json(
:except => [ :created_at, :updated_at, :draft, :id, :publish ], 
:include => 
    :comments => 
        :only => [:body]
    
),
:callback => params[:callback]
end

我想在响应中添加所有文章的索引,如下所示:

@index = Article.find(:all, :select => 'id, title')

我能够做到的唯一方法是将索引和文章都放入哈希或数组中,然后将其放入 JSON。

@response =  :item => @article, :index => @index 

两者的完整代码:

@index = Article.find(:all, :select => 'id, title')

if params[:id]
    @article = Article.find(params[:id])
else
    @article = Article.published.not_draft.by_recent.first
end

@response =  :item => @article, :index => @index 

respond_to do |format|

format.js  render :json => @response.to_json(), :callback => params[:callback]

end

这很好,但现在我无法指定 :include:except 并让它正确呈现。

【问题讨论】:

【参考方案1】:

您应该可以像这样嵌套:include:except 等:

:except => :item => [ :created_at, :updated_at, :draft, :id, :publish ]...

如果这不起作用,请将其设为对象(例如 OpenStruct)而不是哈希。

-- 马库斯

【讨论】:

【参考方案2】:

为了清楚起见,上面的代码与 :include 和 :except 一起使用。通过作品,我的意思是它不会引发错误。问题是它包含索引中每篇文章的 cmets。我只希望包含 :item 的 cmets,而不是索引中列出的任何文章。

我无法将嵌套用作哈希或 OpenStruct 对象。

嵌套在 :include 上会引发错误,嵌套在 :except 上不会引发错误,但什么都不会被过滤掉,:created_at 等仍然会显示出来。

...

@response =  :item => @article, :index => @index 

format.js  render :json => @response.to_json(
:except => :item => [ :created_at, :updated_at, :draft, :id, :publish ], 
:include =>  :item => 
        :comments => 
                :only => [:body]
        
),
:callback => params[:callback]
end

【讨论】:

【参考方案3】:

to_json 有一个 :method 选项,其中包括您命名的任何方法的结果,您可以在该模型上定义一个方法,该方法返回您想要的 JSON 中的其他数据。

【讨论】:

【参考方案4】:

您在问题中暗示了解决方案。您很可能希望构建一个散列以呈现为 JSON。现在最好的方法是为 as_json 方法提供一个实现。 as_json 通过构建包含您希望编码的数据的哈希来提供自定义 to_json 输出的正式方法。

关于 as_json 和 to_json 如何交互的更全面的处理可以在Jonathan Julian's weblog 上找到。

【讨论】:

【参考方案5】:

(请接受答案)

我认为 nirvdrum 提供的链接包含您的答案。我只回答是因为没有人提到encode_json

在您的情况下,您应该只处理as_json。通过构建一个散列(通过各种调用as_json)并将其发送到render :json => ...(不调用to_json)或者通过简单地在您的模型上实现as_json 并让rails 完成所有工作。 (但我怀疑你会需要前者。)

如果您在渲染的响应中确实需要一些花哨的 js,那么您可以在您的类中实现 encode_json(同样,不是 to_json)。例如:

class JsEmptyClosure
  def encode_json(*args)
    "jQuery[\"noop\"] || function()"
  end
  def as_json(*args) self end
end

这现在将使用有效的 js 响应 to_json(但请注意它实际上不是 json)。

【讨论】:

【参考方案6】:

感谢您的提问,我可以为具有多个关联的模型自定义我的 json 格式。

渲染 json:@posts.to_json(

:except => [:created_at, :updated_at, :user_id],

:include =>

:user => :only => [:email, :phone],

:location => :only => [:title, :lat, :lon, :street, :city, :state, :邮编],

:上传 => :only => [:image]

)

【讨论】:

【参考方案7】:

我建议重载 attributes 方法以返回将在 to_json 输出中自动使用的备用哈希。

class Article
   def attributes
      ...  # define your hash that you want to return at the '...'
   end
end

对我来说,这似乎比直接使用 to_json 简单得多。

【讨论】:

以上是关于Ruby on Rails 高级 JSON 序列化的主要内容,如果未能解决你的问题,请参考以下文章

Ruby on Rails 序列化然后反序列化 JSON 中的同一个对象

如何在 ruby​​ on rails 4 中创建高级搜索

Ruby on Rails:高级搜索

Ruby on Rails:高级搜索,nil:Nilclass 的未定义方法 []

Ruby On Rails 中的编组与 ActiveRecord 序列化

在 Ruby on Rails 中,如何渲染 JSON?