Rails 具有自定义 REST collection 架构的 ActiveResource?
Rails ActiveResource with custom REST collection schema?
我正在尝试建立一些在 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 控制台上(rails 为 API 供电的实例)我可以看到
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 到 return 类似:
[
{"first_name": "walter", "last_name": "white"},
{"first_name": "chuck", "last_name": "norris"}
]
当我的 collections 看起来像这样时:
{
"data": [
{"first_name": "walter", "last_name": "white"},
{"first_name": "chuck", "last_name": "norris"}
],
"collection": {
"total_entries": 2
}
}
我现在正在寻找一种自定义 ActiveResource Collection 解析器的好方法,可能像 backbone.js 正在做的事情 (http://backbonejs.org/#Collection-parse) 但不知何故我找不到这个问题的答案很明显。
有什么想法吗?谢谢!
默认情况下,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
我正在尝试建立一些在 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 控制台上(rails 为 API 供电的实例)我可以看到
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 到 return 类似:
[
{"first_name": "walter", "last_name": "white"},
{"first_name": "chuck", "last_name": "norris"}
]
当我的 collections 看起来像这样时:
{
"data": [
{"first_name": "walter", "last_name": "white"},
{"first_name": "chuck", "last_name": "norris"}
],
"collection": {
"total_entries": 2
}
}
我现在正在寻找一种自定义 ActiveResource Collection 解析器的好方法,可能像 backbone.js 正在做的事情 (http://backbonejs.org/#Collection-parse) 但不知何故我找不到这个问题的答案很明显。
有什么想法吗?谢谢!
默认情况下,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