Ruby:当关联对象上的某些内容发生变化时,对其进行修改的解决方案

时间:2012-10-23 14:59:46

标签: ruby-on-rails ruby activerecord associations message-queue

我正在研究这个要求:我有一个非常大的对象关系模型,其中实体的链接非常紧密。举例来说,让我们使用这种关系:建筑物有很多公寓,公寓有很多部门。现在,我想要的是:当任何部门发生变化时,我想“通知”建筑物,或者更好,标记建筑物已“更新”或“修改”。

  • 当前解决方案:我们有一个自编写的实现,我们将分区标记为“影响”构建,并且每次更新分区时都会更新构建的“修改”时间戳。

  • 理想的解决方案:已经存在的“开箱即用”实现(宝石,插件,上帝,也许),这将使我们无法重构我们的实现。

  • 不需要的解决方案:请不要告诉我将所有这些关联标记为:autosave =>真正。我想要一个可排队的解决方案。

当然,欢迎不包含所需解决方案但是提出改进当前解决方案性能的建议的解决方案。由于缺乏理想的解决方案,我们绝对会改进现有解决方案。

小编辑:

此行为必须是通用的。它不仅适用于建筑物案例,而且任何具有关联的模型都可以具有此行为。哪个将始终相同:获取受影响的关联并更新它们。现在,我不想用相同的例程编写不同的观察者。

在性能问题上:更新受影响的关联更新还必须触发其受影响的关联。现在,让我们假设1个建筑物影响100个分区,每个分区影响100个椅子。现在,观察者解决方案仅适用于业务级别。也就是说,我必须实例化每个AR实例,以便观察者可以采取行动。我认为这表现不佳。如果A影响100个B,我用一个DB语句来做。但是,当我使用SQL完成所有操作时,如何触发这些100的观察者?

所以,回到主要更新点:这种行为是通用的,最重要的是,性能必须是最高的(例如,关联可能会触发has_many关联的nxn更新)。

2 个答案:

答案 0 :(得分:3)

您可以使用observer。在audit_observer.rb

中创建名称为app/models的文件
class AuditObserver < ActiveRecord::Observer
  observe :division

  def after_update(division)
    division.logger.info('Division is updated at #{division.updated_at}')
    ######Your logic goes here 
  end
end

答案 1 :(得分:0)

因此,我解决它的方式是关于观察者设计模式实现的各种建议的混合。所以,首先,该模式的基本实现都不适用于我。为什么?我希望有一个模型A的概念观察它的关系B,B通过它的关系A来观察,并且这个观察的例程被定义在其他地方,在(我们称之为)通知器中。

为什么我不能使用Ruby'观察者'库?理论上我可以实现这一点,但观察对象调用一个名为“changed”的方法来通知其观察者,而“changed”是一个被ActiveRecord覆盖的方法,即“脏”库。

为什么我不能使用AR'观察员'?因为在这里观察者是我想要的通知者。该例程未在模型中实现,但我无法说明必须通知哪些其他AR模型。这是一种阻碍。

我是如何解决的?我自己创建了一个库,使用ActiveModel :: Observing库,它允许我实现我想要的功能。我的设计是为了拥有这个DSL:

A类&lt; ActiveRecord的      has_one:b

 observes :b, :on => :create, :notifiers => :update_observer

所以这意味着,当创建b时,会有一个通知程序update_observer,它可以到达b和a并对其执行某些操作。所以,在这种情况下:

class UpdateObserverNotifier < Notifier

  def action(observable, observer)
    observer.update_attributes(updated_at: observable.updated_at)
  end
end

观察者的DSL调用将在各自的类中注入“观察者”和“可观察”行为。 Notifier基类将具有通知行为,并且它将有权访问observable和observer对象,以防observable中的某些内容必须在观察者中进行镜像。如果您的操作触发了观察者的回调,它也会通知观察者本身的潜在观察者。

是的,所以就是这样。感谢您的建议,否则我不会实现它。