2012-06-07 15 views
1

让我们说我们有以下情形:什么是一些常见的模式来确保跨多个系统的Rails模型的数据持久性?

class MyModel < ActiveRecord::Base 
    after_save :throw_after_save 
    after_commit :throw_after_commit 

    private 
    def throw_after_save 
     raise "raising on after_save" 
    end 

    def throw_after_commit 
     raise "raising on after_commit" 
    end 
end 

class MyController < ApplicationController 
    def callback 
    begin 
     MyModel.new(params).save 
    rescue 
     flash[:alert] = "Failed persisting to external system. Try again." 
     Airbrake.notify(
     error_class: "External System Persistence", 
     error_message: "External System Persistence: Failed to persist data", 
     parameters: params 
    ) 
    end 

    redirect_to root_path 
    end 
end 

我们从外部系统(其中用户填写了一些数据和帐户创建一个临时的属性集)获得的回调。

让我们假设我们想在回调给我们之后在本地保存一些数据。在这些数据被保存后,我们要拨打外部系统来完成帐户创建过程。外部系统应该返回一个结果,告诉我们成功的一些额外的数据,我们需要坚持本地。我们也知道,在某些例外的情况下,远程系统上的持久性将不会成功发生(让我们说系统不可用,或者在它们的末端出现问题)。

目标是捕获外部持久性异常以及成功并相应采取行动。在成功的情况下,一切都很棒:附加数据存储在本地,发生redirect_to root_path。但是,在例外的情况下,我们希望向用户指出这一点(可能会将flash[:alert]设置为在视图中显示)。

我们曾试图用ActiveRecord::Callbacks从模型after_saveafter_commit抛出一个异常,并通过设置警报,并可能通过异常的一些异常通知系统(如空中刹车)处理该异常的控制器。在after_save的情况下,模型抛出异常并由控制器捕获,但记录不保存(即使在外部系统出现异常的情况下,我们也需要保存部分数据 - 这不是上可接受的)。在after_commit的情况下,控制器抛出并拾取的例外是而不是,但部分记录仍然存在。这意味着我们不能通知用户该异常(除非我们实施一些通知推送机制 - 这是过度杀伤)。

事实证明,我们可以在模型上设置错误after_save,这很好。但是,这是一个好的一般模式来处理这种情况?

+0

这似乎像它可能是一个非常有用的资源... http://rubysource.com/ddd-for-rails-developers-part-1-layered-architecture/ 通过现在读。 另外: http://railsconf2012.com/sessions/50 – zealoushacker

回答

1

你没有很多选项。既然你所要求的逻辑本身很复杂,我会移动代码将记录保存到其他地方(可能是一个类方法或另一个类,代表一个服务),并且当有人想保存这个特定的对象时,它会有通过这种服务模式。

例如:

class MyModelPersistenceService 

    def save_model(model) 
     result = model.save 
     if result 
     call_external_service 
     end 
    end 

end 

Services不在的Ruby/Rails项目共同但他们是一个很好的适合这种用途的(和滥用AR回调通常会导致难以测试的对象)。

+0

服务模式很有意义。它会封装外部服务持久性,而依靠模型本身来处理。当然,唯一的“问题”是它打破了'instance = Model.new(attributes)'的标准Rails模式,后面跟着'instance.save'。我仍然感兴趣的是,将模型中的逻辑优美地封装在模型中是否可行是为了避免突破常见的Rails模式。大多数情况下,我从纯粹的信息角度对此感兴趣。 – zealoushacker

+0

太糟糕了我今年不在RailsConf上:http://railsconf2012.com/sessions/50 – zealoushacker

+0

http://karmajunkie.com/event-sourcing-talk#1 – zealoushacker

相关问题