Rails 请问怎么往 ActiveModel 的 json 里加 hash 或者 array

birbird · 2014年08月05日 · 最后由 birbird 回复于 2014年08月06日 · 3238 次阅读

我有一个类 class Place < ActiveRecord::Base,之前已经写好了输出成 json 的规则,这个样子的

def as_json_options
  @options={}
  @options[:except] ||= [:created_at, :updated_at]
  @options[:include] ||= {:positions => Position.as_json_options}
  @options[:methods] ||= [:guide_info]
end

其中的 Position 是一个这样的东西

{
    name : "A1",
    tags : ["abc", "xyz"]
}

原来 Place 里包含一个 Position 数组,都是通过 ActiveRecord 映射好的,输出 json 也很正常。 现在需求变了,要求 Place.positions 不是一个数组了,是一个根据 position name 首字母分组的 Hash,类似这样

{
    ...
    positions_ : {
        A : [
            { name : "A1", tags : ["abc", "xyz"] },
            { name : "A2", tags : ["abc", "xyz"] },
            ...
        ],
        B : [
            { name : "B1", tags : ["abc", "xyz"] },
            { name : "B2", tags : ["abc", "xyz"] },
            ...
        ],
        ...
    },
    ...
}

我倒是可以按上述结构构造一个 hash 属性,但我没有办法把这个 hash 按照 as_json 的方式放到输出里,因为他不是 ActiveModel,会报 undefined method `serializable_hash' for #Hash:0x54a4610

我能做到的就是把这个 hash.to_json 当字符串用 @options[:methods] 挂在 json 的一个字段上,但这样 positions_ 里就会有一些不必要的引号,因为 to_json 的时候就带了引号。这样不好。

请问,这该怎么搞? 谢啦先!

一般 本人去覆盖 as_json 方法

def as_json(opt ={})

end

跟此 model 相关的 json 都会修改

#1 楼 @hammer 其实我也是用的覆盖 as_json 的方法,关键是 Place 的 as_json 应该怎么写啊

试试 rails group_by

#3 楼 @hammer 多谢提示。我就是用的 group_by,但卡在 undefined method `key?' for #JSON::Ext::Generator::State:0x37e7db8 问题描述里我就说了,我可以得到这个 hash,但无法把这个 hash 放到 json 里,这样写是不行的

def positions_
  self.positions.group_by{|p| p.name[0]}
end

def as_json_options
  @options={}
  ...
  @options[:methods] ||= [:positions_]
  ...
end

def as_json(options={})
  super(as_json_options)
end

关键是怎么放到输出的 json 里呢

这么复杂就用个 json serializer 吧

请问楼上二位,json serializer 是个啥东西,一个库?一个类?Google 了一下还是不知所措啊。 http://api.rubyonrails.org/classes/ActiveModel/Serializers/JSON.html

没看懂楼主的需求,最终要怎么调用这个方法?

但是有一点建议,不要把复杂 json 输出逻辑写在 model,而放在 view,比如用 jbuilder 模板。

#8 楼 @Rei 多谢您的建议 #9 楼 @HungYuHei 多谢指路,知道要看啥了

需要 登录 后方可回复, 如果你还没有账号请 注册新账号