强制保存!操作失败

问题描述:

我有一个ImagesController,它启动了一个非平凡的保存操作。这里的高级背景:强制保存!操作失败

我有几种不同的物理文件类型来处理我的应用程序。这些每个belongs_to a Binary。当然,可以创建文件,并且此过程涉及将物理文件上传到临时位置,可能验证物理文件(对于大小,类型或其他),然后假设没有问题将文件移动到永久位置然后在适当的表格中创建数据库记录(为了我的问题,我们使用imagesbinaries)。

Image属于Binary并且有BinaryObserver观察Image类。在那个观察者类中,有一个before_create()方法,它告诉Binary类上传图像的物理文件并在数据库中保存相关记录(包括名称,路径,URI信息等)。

观察者类方法所做的一件事是测试原始模型中的回调方法,在这种情况下为Image。如果方法存在并因任何原因返回false,那么我需要保存操作失败。我无法弄清楚如何做到这一点。

在我的控制器的create()方法,我有:

if @image.save! 
    flash[:notice] = "Successfully created image." 
    redirect_to @image 
else 
    flash[:notice] = "Upload failed." 
    render :action => 'new' 
end 

我无法弄清楚如何触发else块。在我BinaryObserver类,我有:

def before_create(model) 
    binary = Binary.new.upload(model.upload) 

    if !model.respond_to?('before_file_save') || model.before_file_save() 
     binary   = binary.store() 
     model.binary_id = binary.id 
     model.active = 1 

     return true 
    else 
     # binary.destroy() 
     File.delete(File.join(Rails.root, binary.path)) 
     return false 
    end 
end 

目前,Image.before_file_save()仅返回false。物理文件被删除,但保存并未失败,并且我的控制器显示一条错误消息,表明其show()方法找不到图像(这是合理的,因为图像未保存且物理文件已被删除)。

如果观察者类'before_create()方法返回false,我该如何强制保存操作失败?

谢谢。

这是我的理解是,如果操作失败,在Model方法上使用bang(!)语法将引发异常。显然,保存并不失败,但Observer需要让你的控制器知道出了问题。我会按照这样做的相同AR的方式,有例外:

begin 
    @image.save! 
    flash[:notice] = "Successfully created image." 
    redirect_to @image 
rescue YourObserverException => e 
    flash[:notice] = "Upload failed." 
    render :action => 'new' 
end 

这意味着观察者没有返回true,但如果上传失败确实引起YourObserverException(你在哪里returning false)。

+1

我更喜欢你的方法 - 更清洁。 – 2009-08-19 23:44:52

+0

谢谢,这个工作很好,一旦我想出了如何在Ruby中引发异常。我通常是异常处理的重要用户,但我想我只是假定返回false会使保存无效。科迪上面说的是合理的,但是模型完整性仍然完好无损,因为这是在保存之前发生的。 – 2009-08-20 00:15:42

您的观察者IS仍在基本上位于顶部的ActiveRecord Transaction内部运行。所以DB明智的你应该仍然有诚信。但是为了将这些信息传递给顶端,我会在返回false之前在对象中设置一个实例变量。由于控制器仍然在Observer的同一个对象上运行,因此可以使用相同的信息。

...在你的观察 model.is_valid =假#or_something_went_wrong =真等 返回false

然后,只需对相应的操作在您的控制器。