Ruby on rails 包装#找到每一个并亲自展示类似的功能 背景

Ruby on rails 包装#找到每一个并亲自展示类似的功能 背景,ruby-on-rails,activerecord,Ruby On Rails,Activerecord,我已经将一些功能划分为一个服务/类库,试图将此功能与我的应用程序的其余部分清晰地分开。从现在起我称之为服务 目前,这个小服务将ActiveRecord对象泄漏到调用代码中,但我更希望分离更干净 代码示例 服务的API: module MyService # This method should really be read-only, but we're exposing # ActiveRecord objects, so the caller can mess around wit

我已经将一些功能划分为一个服务/类库,试图将此功能与我的应用程序的其余部分清晰地分开。从现在起我称之为服务

目前,这个小服务将ActiveRecord对象泄漏到调用代码中,但我更希望分离更干净

代码示例 服务的API:

module MyService
  # This method should really be read-only, but we're exposing 
  # ActiveRecord objects, so the caller can mess around with them. :(
  def self.people
    Person.all
  end
end
调用代码示例

MyService.people.find_each(batch_size: 500) do |person|
  # Do something useful with person
end
我认为在将ActiveRecord对象返回到调用代码之前将其转换为结构可能是实现这一点的一个想法

问题 这里只有一个问题:Person模型有数千个条目。因此,我的天真方法将实例化数千个ActiveRecord,将其内容复制到数千个结构中,然后返回。这显然是一个巨大的内存消耗

我希望调用代码能够批量获取Person对象,并避免MyService.people一次实例化所有记录


我真的无法完全理解这是如何实现的。有人能给我指出正确的方向吗?

您可以在
MyService
上编写自己的方法,该方法需要一个块,并在
生成之前将
转换为只读版本

module MyService
  ReadOnlyPerson = Struct.new(:first_name, :last_name)

  def self.each_person
    Person.find_each do |person|
      read_only_person = ReadOnlyPerson.new(person.first_name, person.last_name)
      yield read_only_person
    end
  end
end

如果您想保留完整的
ActiveRecord
功能(除了编写),还可以直接用
readonly标记实例

def self.each_person
  Person.find_each do |person|
    person.readonly!
    yield person
  end
end
您仍然可以分配诸如
person.first\u name='Phil'
之类的内容,但尝试
保存将引发异常:

ActiveRecord::ReadOnlyRecord: Person is marked as readonly

令人惊叹的。这很好用,谢谢你给我的建议,让
ActiveRecord
readonly成为一个只读的,在我决定不再是一个纯粹主义者的情况下,它可能会派上用场!
ActiveRecord::ReadOnlyRecord: Person is marked as readonly