如何使用 JSON 服务作为 Rails 3.2 应用程序的模型?
我想将模型方法链接到 JSON 请求,例如
MyModel.create生成 JSON 请求以创建新记录MyModel.find生成 JSON 请求以检索记录并将 JSON 响应解码为模型对象
构建此类功能的首选方法是什么?我正在考虑的一个选项是创建一个自定义DataMapper适配器。
谢谢。
更新:
请注意,我不能使用 ActiveResource,因为这需要 JSON 服务以某种方式响应,而在这种情况下它不需要。
如何使用 JSON 服务作为 Rails 3.2 应用程序的模型?
我想将模型方法链接到 JSON 请求,例如
MyModel.create生成 JSON 请求以创建新记录MyModel.find生成 JSON 请求以检索记录并将 JSON 响应解码为模型对象构建此类功能的首选方法是什么?我正在考虑的一个选项是创建一个自定义DataMapper适配器。
谢谢。
更新:
请注意,我不能使用 ActiveResource,因为这需要 JSON 服务以某种方式响应,而在这种情况下它不需要。
简短的回答:这取决于您的 JSON 服务。
对于初学者来说,服务是 RESTful 的吗?如果是这样,你很幸运。ActiveResource已死,因此我不建议使用它,但代码本身将为创建一组包装器方法(如访问您的 API 和操作记录)提供一个很好的起点,就像 ActiveRecord 在数据库中创建和查询记录create一样。find如果您的 API 是 RESTful 的,这相对容易,因为rails 是围绕 RESTful-ness 构建的,因此两者之间的映射变得更加清晰。
这篇文章总结的很好:
Rails 使得构建遵循 REST 原则的 Web 服务变得非常容易,并且与 Web 浏览器和可编程 Web 一样好。事实上,很多这种简单性直接来自于遵循这些原则。我们不必告诉我们的客户如何创建、读取、更新或删除资源,所有这些都来自使用正确的 HTTP 方法。我们所要做的就是将我们的客户指向正确的位置。
如果您的服务不是RESTful 的,从我认为其他问题的评论来看可能是这种情况,那么您的工作将为您完成。ActiveModel 不会为您完成这项工作:create在ActiveRecord::Persistence中find定义,在ActiveRecord::FinderMethods中定义。它们不在 ActiveModel 中。ActiveResource 能够相当容易地复制它们,因为它假设了它所连接的服务类型(即它是 RESTful 的,加上其他一些东西)。
ActiveModel 提供的所有其他东西使 rails 在处理模型方面如此有用:它的验证系统、序列化方法、属性更改的脏跟踪、回调(before_save、after_save等)、翻译/本地化等等。这些都是非常有用的功能,但它们仍然给您留下了包装 API 调用的问题。
因此,根据我虽然有限的经验,这就是我的建议(请参阅我的最后说明):
create,find以及您想要拥有的任何其他类似 ActiveRecord 的功能。您可能希望使用像
Faraday或HTTParty这样的 gem来实际向 API 发出请求,而不是直接使用 Net::HTTP。(我从未使用过 DataMapper,因此无法对此发表评论。)这将为您提供将 JSON 服务用作 Rails 模型的大部分方法。
作为记录,我在实际实现这种事情方面的经验仅限于构建一个用于访问 XML API 的 API 包装器(正在开发中)。包装器有一个类,其中包括用于验证 API 查询的 ActiveModel 验证器。我发现 ActiveModel 验证器对于保证 API 被正确访问非常有用,但包装器仅用于从 API 获取记录,而不是实际创建或更新它们,因此接口比我预期的要容易得多你会建造的。
我认为您正在寻找的是ActiveResource,您可以使用它而不是使用ActiveRecordRESTful JSON API 看到这个链接和这个(apidock)
最好的方法是实现一个 ActiveModel。这个railscast涵盖了基础知识。
我在我的 gem“ otrs_connector ”中做到了这一点......它不适用于您的服务,但它可以让您了解如何做到这一点......我采用的方法可能不是最好的,需要重构有点,但它确实有效,而且做得很好。
如果 Web 服务超出了正常的“Rails 方式”做事,我会推荐HTTParty。为响应您想要的响应的 Web 服务创建代理非常容易。
例如,这是他们访问 Twitter 时间线的示例
class Twitter
include HTTParty
base_uri 'twitter.com'
def initialize(u, p)
@auth = {:username => u, :password => p}
end
# which can be :friends, :user or :public
# options[:query] can be things like since, since_id, count, etc.
def timeline(which=:friends, options={})
options.merge!({:basic_auth => @auth})
self.class.get("/statuses/#{which}_timeline.json", options)
end
def post(text)
options = { :query => {:status => text}, :basic_auth => @auth }
self.class.post('/statuses/update.json', options)
end
end
twitter = Twitter.new(config['email'], config['password'])
pp twitter.timeline