代码之家  ›  专栏  ›  技术社区  ›  nakwa

使用自定义REST集合模式的Rails ActiveResource?

  •  1
  • nakwa  · 技术社区  · 9 年前

    我试图在active_resource gem(ActiveResource)之上建立一些Rails模型

    module Core
        class RestResource < ActiveResource::Base
            self.format = :json
        end
    end
    
    module Core
        module API
            class BaseModel < ::Core::RestResource
            self.site = ENV['API_URI']
            self.headers['Api-Token'] = ENV['API_TOKEN']
            end
        end
    end
    
    module Core
        module API
            class MyModel < ::Core::API::BaseModel
            end
        end
    end
    

    我正在尝试运行rails控制台,如下所示

    2.3.1 :001 > MyModel = Core::API::MyModel
     => Core::API::MyModel 
    2.3.1 :002 > MyModel.all
    ArgumentError: expected an attributes Hash, got ["data", [{"first_name"=>"walter", "last_name"=>"white", "timestamp"=>1478515925}]]
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/bundler/gems/activeresource-f4bec7f8f389/lib/active_resource/base.rb:1377:in `load'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/bundler/gems/activeresource-f4bec7f8f389/lib/active_resource/base.rb:1124:in `initialize'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/bundler/gems/activeresource-f4bec7f8f389/lib/active_resource/base.rb:1051:in `new'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/bundler/gems/activeresource-f4bec7f8f389/lib/active_resource/base.rb:1051:in `instantiate_record'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/bundler/gems/activeresource-f4bec7f8f389/lib/active_resource/base.rb:1047:in `block in instantiate_collection'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/bundler/gems/activeresource-f4bec7f8f389/lib/active_resource/collection.rb:68:in `block in collect!'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/bundler/gems/activeresource-f4bec7f8f389/lib/active_resource/collection.rb:8:in `each'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/bundler/gems/activeresource-f4bec7f8f389/lib/active_resource/collection.rb:8:in `each'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/bundler/gems/activeresource-f4bec7f8f389/lib/active_resource/collection.rb:68:in `collect!'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/bundler/gems/activeresource-f4bec7f8f389/lib/active_resource/base.rb:1047:in `instantiate_collection'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/bundler/gems/activeresource-f4bec7f8f389/lib/active_resource/base.rb:1016:in `find_every'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/bundler/gems/activeresource-f4bec7f8f389/lib/active_resource/base.rb:923:in `find'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/bundler/gems/activeresource-f4bec7f8f389/lib/active_resource/base.rb:949:in `all'
        from (irb):2
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/gems/railties-5.0.0.1/lib/rails/commands/console.rb:65:in `start'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/gems/railties-5.0.0.1/lib/rails/commands/console_helper.rb:9:in `start'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/gems/railties-5.0.0.1/lib/rails/commands/commands_tasks.rb:78:in `console'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/gems/railties-5.0.0.1/lib/rails/commands/commands_tasks.rb:49:in `run_command!'
        from /Users/nakwa/.rvm/gems/ruby-2.3.1/gems/railties-5.0.0.1/lib/rails/commands.rb:18:in `<top (required)>'
        from bin/rails:4:in `require'
        from bin/rails:4:in `<main>'
    2.3.1 :003 > 
    

    在我的rails控制台(为API提供动力的rails实例)上,我可以看到

    Started GET "/v1/my_model.json" for ::1 at 2016-11-08 16:42:11 +0100
    Processing by V1::MyModelController#index as JSON
      MyModel Load (0.2ms)  SELECT "my_model".* FROM "my_model"
    [active_model_serializers] Rendered V1::MyModelSerializer with MyModelSerializer::Adapter::Attributes (2.2ms)
    Completed 200 OK in 13ms (Views: 2.8ms | ActiveRecord: 1.8ms)
    

    我的理解是,Rails activeresource期望JSON API返回如下内容:

    [
      {"first_name": "walter", "last_name": "white"}, 
      {"first_name": "chuck", "last_name": "norris"}
    ]
    

    当我的收藏看起来像这样时:

    {
      "data": [
        {"first_name": "walter", "last_name": "white"}, 
        {"first_name": "chuck", "last_name": "norris"}
      ],
      "collection": {
        "total_entries": 2
      }
    }
    

    我现在正在寻找一种定制ActiveResourceCollection解析器的好方法,可能类似于主干。js正在做什么( http://backbonejs.org/#Collection-parse )但不知何故,我无法找到这个问题的明确答案。

    知道吗?谢谢

    1 回复  |  直到 9 年前
        1
  •  5
  •   igneus    8 年前

    默认情况下,ActiveResource对API返回的数据格式有很强的期望,但您可以提供自己的 总体安排 对于这样的场景。

    任何实现一些预期方法的Ruby对象都可以用作格式。ActiveResource本身将格式实现为模块,因此我们将坚持这一约定。

    作为一个懒惰的人,我会重新使用标准 JsonFormat 实现和仅重写方法 decode :

    module CustomJsonFormat
      include ActiveResource::Formats::JsonFormat
    
      extend self
    
      def decode(json)
        ActiveSupport::JSON.decode(json)['data']
      end
    end
    

    现在我们只告诉ActiveResource子类使用它:

    class BaseModel < ActiveResource::Base
      self.format = CustomJsonFormat
    
      # ... set self.site, self.headers etc.
    end