【问题标题】:How to modify JSON returned from Rails controller如何修改从 Rails 控制器返回的 JSON
【发布时间】:2014-03-10 02:15:27
【问题描述】:

我在 Rails 控制器中返回 JSON 的标准机制是:

respond_to do |format|
  format.html
  format.json { render json: @cars }
end

有没有办法修改@cars JSON?特别是我只想在其中添加 4 个额外的字段。

更新:抱歉,我应该多解释一下。 @cars 包含 Car 对象的列表。我想为 JSON 中的每个 Car 对象添加 4 个字段。这对于特定控制器来说是唯一,因此我不想创建 as_json 方法,因为这会影响此类的其他 JSON。

【问题讨论】:

  • @cars 是来自 Car Model 的结果集吗?这 4 个字段对于每条记录也是唯一的,还是与 cars 的集合相邻的超集?
  • 您的意思是,您想在汽车对象之外添加 4 个额外字段?喜欢:{total_records: 4, current_page: 1, per_page: 2, cars: [{...},{...}]}
  • 对不起,我应该澄清一下。更新问题。
  • @at.:正如我在另一条评论中所写,您可以轻松地使用 to_json(:exclude => [], :methods => [])。有关详细信息,请参阅我的答案
  • @at。您可以将通常传递给 #as_json 方法的所有选项传递给控制器​​中的 #to_json。或者,您可以创建一个自定义 ActiveModelSerializer 并且只在控制器中使用一次:render json: @cars, serializer: MyCustomCarSerializer

标签: ruby-on-rails json


【解决方案1】:

有两种方法可以修改返回的json的结构。

  1. 覆盖模型上的#as_json 方法

    model Car < ActiveRecord::Base
    
      def as_json(options={})
        opts = {
          :only => [:id, :name],
          :methods => [:custom_method]
        }
    
        super(options.merge(opts))
      end
    
      def custom_method
        # some extra info (possibly calculated values)
      end
    
    end
    
  2. 您可以使用active_model_serializer gem。这是我的首选方法,因为它具有一些内置的便利性。

    class CarSerializer < ActiveModel::Serializer
      attributes :id, :name, :custom_method
    
      def custom_method
        # method only available within serializer
      end
    end
    

【讨论】:

    【解决方案2】:

    如果你想编辑 json,那么你可以使用ActiveSupport::JSON.decode 来解码 json。它将为您提供一个易于修改的哈希数组,然后您可以使用 to_sosn 将其转换为 json

    示例:我使用 Rails 控制台进行演示。您只需要最后一部分。

    >> cars = [{id: 1,name: 'foo'}, {id:2, name: 'bar'}]
    [{:id=>1, :name=>"foo"}, {:id=>2, :name=>"bar"}]
    
    >> json = cars.to_json
    "[{\"id\":1,\"name\":\"foo\"},{\"id\":2,\"name\":\"bar\"}]"
    
    >> parsed_json = ActiveSupport::JSON.decode json
    [{"id"=>1, "name"=>"foo"}, {"id"=>2, "name"=>"bar"}]
    

    然后您可以迭代该数组并在必要时进行修改并转换回 json

    【讨论】:

    • 对不起,我不喜欢投反对票,但我发现疯狂获取内存对象,将其转换为字符串,将其重新转换为内存对象(当您已经拥有它时),然后将其发送为一个 json,你的内存使用量增加了三倍,浪费了 cpu 周期来做一些可以做得更好的事情,比如 as_json 方法或github.com/rails-api/active_model_serializers
    • 我刚刚在控制台中展示了这个过程。他只需要最后一步
    • @Fire-Dragon-DoL 请看问题的更新部分,as_json 好像没什么用
    • @object.as_json(:except => ['created_at', 'updated_at'], :methods => ['dis', 'val']) 并且可以直接在控制器中调用。我不确定你是否可以直接在 to_json 方法上使用它。
    【解决方案3】:

    如果你必须做一次,你应该这样使用to_jsonhttp://apidock.com/rails/ActiveRecord/Serialization/to_json),直接在你的控制器中:

    @object.to_json(:except => ['created_at', 'updated_at'], :methods => ['method1', 'method2'])
    

    :methods 中,您可以指定要包含的其他方法。

    activemodel_serializer 仅应在您经常使用时使用(例如在 JSON API 上),如果您在项目中只使用一次,则不应使用。

    如果您实际使用的是 Rails 4,您也可以使用默认的 Rails 4 构建器。
    请注意,用于构建 JSON 的最著名 gem 是 RABL,但我更喜欢 activemodel_serializer。还有一个很赞的railscasts available for free

    【讨论】:

    • 喜欢to_json 方法,但是如何将它与render json: @cars 一起使用?而不是@cars 我可以通过@cars.to_json(...)?
    • 我不知道这个,我的意思是,我做到了,但我不知道“官方”的方式,我想你可以只渲染 @obj.to_json(blabla) 而没有别的,否则使用 :inline 或 :text 之类的,甚至更好,我建议您为此提出不同的问题。无论如何,这是文档:guides.rubyonrails.org/layouts_and_rendering.html#using-render
    • 你可以查看这个帖子:jonathanjulian.com/2010/04/rails-to_json-or-as_json 有一些关于它的建议。更好的是,检查这个清楚解释这一点的 stackoverflow 问题:stackoverflow.com/questions/2572284/…
    • 看起来这是正确的,尽管as_json 似乎比to_json 更合适。 as_json 只是创建数据结构,to_json 也渲染它。
    【解决方案4】:

    我认为它可以使用一种方法来执行添加字段过程并呈现返回结果。以下内容是否适合您:

    在助手中

    def some_method(in_param, from_which_controller)
      return_array = Array.new
      obj_array = JSON.parse(in_param);
      obj_array.each do |obj|
        case from_which_controller
          when from_controller_a
             # add the field to obj or some other thing
          when ...........
             # add the field to obj or some other thing
        end
        return_array << obj # or new obj instead of obj
      end
      return return_array.to_json
    end
    

    在您的控制器中:

    respond_to do |format|
      format.html
      format.json { render json: some_method(@cars, this_controller) }
    end
    

    【讨论】:

      【解决方案5】:

      您还可以添加自定义或嵌套字段,例如:

      class MyModel < ActiveRecord::Base
      
        def as_json(options)
          super(options).merge({
            "custom" => "myvalue",
            :name => self.name.titleize,
            "result" => self.my_method(self.value1)
          })
        end
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-19
        • 2013-09-20
        相关资源
        最近更新 更多