使用 :include 时将 Rails 中的 JSON 数据展平

Flatten JSON data in Rails when using :include

我使用“#111 Advanced Search Form (revised)”教程向我的应用程序添加了一个 "Advance Search",并为其创建了一个 API。一切正常,但现在我正在尝试显示 JSON 数据。

这是 cURL 命令:

curl -v -H 'Content-Type: application/json' -H 'Accept: application/json' -X 
GET http://0.0.0.0:3000/api/searches/129

这是 Curl 命令的结果(请注意括号[ ],因此这是一个哈希数组。):

[{"id":4,"state_id":5,"name":"School Liason Officer","created_at":"2014-10-16T03:13:00.000Z",
"updated_at":"2014-10-16T03:13:00.000Z","state":{"name":"California"}}]

但我想更改 JSON 结果,以便状态名称以某种方式与 JSON 数据扁平化。

有谁知道我该怎么做,或者是否有可能展平数据?

这是我想要的示例:

[{"id":4,"state":"California","name":"School Liason Officer","created_at":"2014-10-16T03:13:00.000Z",
"updated_at":"2014-10-16T03:13:00.000Z"}]

型号:

class State < ActiveRecord::Base  
  has_many :district_resources

end

class DistrictResource < ActiveRecord::Base
  belongs_to :state

end

class Search < ActiveRecord::Base

  def district_resources
    @district_resources ||= find_district_resources
  end

  def find_district_resources
    district_resources = DistrictResource.order(:name)
    district_resources = district_resources.where(state_id: state_id) if state_id.present?
    district_resources
  end

end

API 控制器:

module Api
  module V1
    class SearchesController < ApplicationController

      respond_to :json

      def show
        @search = Search.find(params[:id])
        @searches = []
        (@searches << @search.district_resources).flatten!

        json = @searches.to_json

        def flatten_hash(h)
          new_hash = {}

          ###I get an error here undefined method `each_pair' for Array
          h.each_pair do |key, val|
            if val.is_a?(Hash)
              new_hash[key] = val.values.join(',')
            else
              new_hash[key] = val
            end
          end
          new_hash
        end

        flattened_hash = flatten_hash(JSON.parse(json))
        flattened_hash.delete("state_id")

        respond_to do |format|

          ###How can i merge the state name with the json results
          format.json { render :json => flattened_hash.to_json(:include => [:state => {:only => [:name]}] )}
        end
      end

    end
  end
end

错误

undefined method `each_pair' for #<Array:0x007f8d727b5168>

您可以随心所欲地操作它,即将它传递给另一个变量,使用方法调用等:

  my_json["state"] = my_json["state"]["name"]
  my_json.delete("state_id")

这会将 state => 设置为 name => 的值,然后删除不需要的 state_id =>

我支持 Beartech 的评论,但假设这是不可能的,那么就这样做

require 'json'

def flatten_hash(h)
  new_hash = {}
  h.each_pair do |key, val|
    if val.is_a?(Hash)
      new_hash[key] = val.values.join(',')
    else
      new_hash[key] = val
    end
  end
  new_hash
end

json = '{"id":4,"state_id":5,"name":"School Liason Officer","created_at":"2014-10-16T03:13:00.000Z", "updated_at":"2014-10-16T03:13:00.000Z","state":{"name":"California"}}'
flattened_hash = flatten_hash(JSON.parse(json).to_hash)
flattened_hash.delete("state_id")

给予

{"id"=>4, "name"=>"School Liason Officer", "created_at"=>"2014-10-16T03:13:00.000Z", "updated_at"=>"2014-10-16T03:13:00.000Z", "state"=>"California"}

我结合了上面的两个答案来得到我需要的。 :)

  def show
    @search = Search.find(params[:id])
    @searches = []
    (@searches << @search.district_resources).flatten!

    json = @searches.to_json(:include => [:state => {:only => [:name]}] )

    def flatten_hash(h)
      new_hash = []
      h.each do |val|
        if val.is_a?(Hash)
          val["state"] = val["state"]["name"]
          val.delete("state_id")
          (new_hash << val).flatten!
        else
          new_hash << val
        end
      end
      new_hash
    end

    flattened_hash = flatten_hash(JSON.parse(json))

    respond_to do |format|
      format.html
      #(:include => [:state => {:only => [:name]}] )
      format.json { render :json => flattened_hash.to_json }
    end
  end