【问题标题】:Using a JSON service as a Rails model使用 JSON 服务作为 Rails 模型
【发布时间】:2012-08-02 23:44:51
【问题描述】:

如何使用 JSON 服务作为 Rails 3.2 应用程序的模型?

我想将模型方法链接到 JSON 请求,例如

  • MyModel.create 生成 JSON 请求以创建新记录
  • MyModel.find 生成 JSON 请求以检索记录并将 JSON 响应解码为模型对象

构建此类功能的首选方法是什么?我正在考虑的一个选项是创建一个自定义 DataMapper 适配器。

谢谢。

更新:
请注意,我不能使用 ActiveResource,因为这需要 JSON 服务以某种方式响应,而在本例中它不需要。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 json model


    【解决方案1】:

    简短回答:这取决于您的 JSON 服务。

    对于初学者来说,服务是 RESTful 的吗?如果是这样,你很幸运。 ActiveResource 是dead,所以我不建议使用它,但代码本身将为创建一组包装方法(如createfind)提供一个很好的起点,以访问您的API 并以ActiveRecord 的方式操作记录在数据库中创建和查询记录。如果您的 API 是 RESTful 的,这相对容易,因为 rails is built around RESTful-ness,因此两者之间的映射变得更加清晰。

    This article总结得很好:

    Rails 使构建遵循 REST 原则的 Web 服务变得非常容易,并且与 Web 浏览器和可编程 Web 一起工作同样出色。事实上,很多这种简单性直接来自遵循这些原则。我们不必告诉我们的客户端如何创建、读取、更新或删除资源,所有这些都来自使用正确的 HTTP 方法。我们所要做的就是将我们的客户指向正确的位置。

    如果您的服务不是 RESTful,从我认为其他问题的 cmets 判断可能是这种情况,那么您的工作将为您完成。 ActiveModel 不会为您完成这项工作:createActiveRecord::Persistence 中定义,findActiveRecord::FinderMethods 中定义。 它们不在 ActiveModel 中。 ActiveResource 能够相当容易地重现它们,因为它会假设它所连接的服务类型(即它是 RESTful 以及其他一些东西)。

    ActiveModel 提供的所有其他东西使 rails 在处理模型方面如此有用:它的验证系统、序列化方法、属性更改的脏跟踪、 回调(before_saveafter_save 等)、翻译/本地化等。这些都是非常有用的函数,但它们仍然会给您带来封装 API 调用的问题。

    根据我虽然有限的经验,我会推荐以下内容(请参阅我的最后说明):

    1. 首先,仔细查看您的 API 并确定它与 RESTful 的距离有多近。如果它不是 RESTful,您将不得不考虑如何解决这个问题,以便您可以将其视为 RESTful 服务。 O'Reilly 的 RESTful Web Services(特别是第 2 章“编写 Web 服务客户端”)是有关如何执行此操作的一个很好的参考。
    2. 围绕它创建一个 API 包装器,实现 createfind 以及您想要拥有的任何其他类似 ActiveRecord 的功能。你可能想要使用像这样的宝石 FaradayHTTParty 用于实际向 API 发出请求,而不是直接使用 Net::HTTP。 (我从未使用过 DataMapper,因此无法对此发表评论。)
    3. 包含您想要使用的任何 ActiveModel 元素,以使您的包装类更像一个 rails 模型:验证、序列化等。在 Rails 4 中,您实际上可以使用新的准系统 ActiveModel::Model 包含所有内容。

    这将为您提供将 JSON 服务用作 Rails 模型的大部分方法。

    为了记录,我在实际实现这种事情方面的经验仅限于构建一个用于访问 XML API 的 API 包装器(正在开发中)。包装器有一个类,其中包括用于验证 API 查询的 ActiveModel 验证器。我发现 ActiveModel 验证器对于保证 API 被正确访问非常有用,但包装器仅用于从 API 获取记录,而不是实际创建或更新它们,因此接口比我预期的要容易得多你会建造的。

    【讨论】:

    • 感谢您提供如此全面的答案。幸运的是,JSON 服务是 RESTful 的,只是它没有以 ActiveResource 期望的方式响应。现在我知道 ActiveResource 已经死了,我将避免使用它,而是阅读您链接到的 DZone 文章。再次感谢!
    • 哦,好消息!在这种情况下,任务应该不会太难。即使您没有使用 ActiveResource,您也可以尝试查看代码以了解其工作原理。
    • 如果你还在做这件事,其他一些可能会有所帮助的宝石:github.com/filtersquad/api_smithgithub.com/remiprev/hergithub.com/apotonick/roar
    【解决方案2】:

    我认为您正在寻找的是 ActiveResource,您可以使用它而不是 ActiveRecord 来使用 RESTful JSON API 请参阅 this linkthis (apidock)

    【讨论】:

    • 谢谢。不幸的是,这似乎要求 JSON API 以某种方式响应,而我正在使用的那个没有。例如,如果创建了新记录,它会以 OK 响应,而不是新记录的 JSON 表示。
    【解决方案3】:

    最好的方法是实现一个 ActiveModel。这个railscast 涵盖了基础知识。

    【讨论】:

    • 谢谢,我去看看。 ActiveModel 比 DataMapper 有什么优势?
    • ActiveModel 包含在 Rails 中,因此您可以立即获得更好的支持。
    【解决方案4】:

    我只是在我的 gem "otrs_connector" 中执行此操作...它不适用于您的服务,但它可以让您了解如何执行此操作...我采用的方法可能不是最好的并且需要进行一些重构,但它确实有效,而且做得很好。

    【讨论】:

    • 谢谢,我看看这个。
    【解决方案5】:

    如果 web 服务超出了正常的“Rails 方式”的处理方式,我会推荐HTTParty。为 web 服务创建一个 Proxy 非常容易,它可以根据您的需要做出响应。

    例如,这是他们访问 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
    

    【讨论】:

    • 谢谢,这是一个有趣的替代方案,但我希望 JSON 服务能够像传统的 Rails 模型一样运行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-06
    • 2011-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多