Rails 中的模型不必做数据库操作,它们只是普通的类。通常,当您从 ActiveRecord::Base 子类化它们时,它们会充满 ActiveRecord 的魔力。
您可以使用诸如Virtus之类的 gem来为您提供具有属性的模型。对于验证,您可以使用Vanguard。如果您想要一些接近ActiveRecord
但没有数据库的东西并且正在运行 Rails 3+,您还可以将其包含ActiveModel
到您的模型中以获取属性和验证,并让它们在表单中工作。有关详细信息,请参阅Yehuda Katz 的帖子。
在您的情况下,这将取决于您将使用的数据。例如,如果所有数据源都具有相同的基本格式,您可以创建自己的基类来保留您希望在各个类之间共享的所有逻辑(继承)。
如果您有几种不同类型的数据进入,您可以创建模块来封装不同类型的行为,并将您需要的模型包含在适当的类(组合)中。
通常,尽管您可能希望在远程 API 中为每个资源提供一个类,该类与您拥有的任何域逻辑进行一对一的映射。您可以通过多种不同的方式来实现这一点,但遵循 ActiveRecord 使用的方法命名可能是一个好主意,因为您在构建类结构时学习了 ActiveRecord,并且如果您的 API 看起来和工作起来像 ActiveRecords,它将帮助其他 Rails 开发人员。
根据您希望能够对对象执行的操作来考虑它(这就是 TDD 的用武之地)。您希望能够获取集合Model.all
、特定元素Model.find(identifier)
、将更改的元素推送到远程服务updated_model.save
等等。
这些方法内部的实际逻辑将取决于远程服务。但是您可能希望每个模型类都保存一个指向其资源端点的 url,并且您肯定希望将逻辑保留在模型中。所以而不是:
response = api_client.get_user(123)
User user = User.new(response)
你会去做的
class User
...
def find id
@api_client.get_user(id)
end
...
end
User.find(123)
或者更有可能
class ApiClient
...
protected
def self.uri resource_uri
@uri = resource_uri
end
def get id
# basically whatever code you envisioned for api_client.get_user
end
...
end
class User < ApiClient
uri 'http://path.to.remote/resource.json'
...
def find id
get(id)
end
...
end
User.find(123)
基本原则:将所有共享逻辑收集在一个类(ApiClient)中。基于每个资源(用户)的子类。将所有逻辑保留在您的模型中,系统的任何其他部分都不必知道它是数据库支持的应用程序还是您使用的是外部 REST API。最重要的是,如果您可以将集成逻辑完全保留在基类中。这样,如果外部数据源发生变化,您只有一个地方可以更新。
至于另一种方式,Rails 有几个很好的方法可以将对象转换为 JSON。从 to_json 方法到使用诸如 RABL 之类的 gem 来获得 JSON 对象的实际视图。
您可以使用部分 ActiveRecord 模块获得验证。从 Rails 4 开始,这是一个名为 ActiveModel 的模块,但您可以在 Rails 3 中完成它,并且有几个在线教程,尤其是RailsCast。
性能不会是问题,除非您在调用远程服务时可能会遇到问题,如果网络很慢,您会遇到。其中一些可能有助于缓存(有关详细信息,请参阅我的另一个答案),但这也取决于您使用的数据。
希望这能让你走上正确的轨道。如果你想更深入地了解如何设计这些结构,你应该选择一本关于这个主题的书,例如Practical Object-Oriented Design in Ruby: An Agile Primer by Sandi Metz。