Reputation: 41236
I have an ImagesController
that kicks off a non-trivial save operation. Here's the high-level background:
I have several different physical file types to deal with in my application. Each of these belongs_to
a Binary
. Files can be created, of course, and this process involves uploading a physical file to a temporary location, possibly validating the physical file (for size, type or whatever) and then, assuming no issues, moving the file to a permanent location before creating database records in the appropriate tables (let's use images
and binaries
for the purpose of my question).
An Image
belongs to a Binary
and there's a BinaryObserver
that observes the Image
class. In that observer class, there's a before_create()
method that tells the Binary
class to upload the image's physical file and save a related record in the database (with name, path, URI info, etc.).
One of the things that the observer class method does is test for a callback method in the original model, Image
in this case. If the method exist and returns false for any reason, then I need for the save operation to fail. I can't figure out how to do that properly.
In my controller's create()
method, I have:
if @image.save!
flash[:notice] = "Successfully created image."
redirect_to @image
else
flash[:notice] = "Upload failed."
render :action => 'new'
end
I can't figure out how to trigger the else
block. In my BinaryObserver
class, I have:
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
At the moment, Image.before_file_save()
simply returns false. The physical file is getting deleted, but the save isn't failing and my controller displays an error message that its show()
method can't find the image (which makes sense since the image wasn't saved and the physical file was deleted).
How can I force the save operation to fail if the observer class' before_create()
method returns false?
Thanks.
Upvotes: 0
Views: 1084
Reputation: 2233
It's my understanding that using the bang (!) syntax on Model methods will raise an exception if the operation fails. Obviously, the save isn't failing, but the Observer needs to let your controller know something went wrong. I would follow the same AR way of doing it, with exceptions:
begin
@image.save!
flash[:notice] = "Successfully created image."
redirect_to @image
rescue YourObserverException => e
flash[:notice] = "Upload failed."
render :action => 'new'
end
This would mean the observer doesn't return true, but does raise YourObserverException
if the upload fails (where you are returning false
).
Upvotes: 1
Reputation: 32748
Your Observer IS still running inside an ActiveRecord Transaction that is created basically at the top. So DB wise you should still have integrity. But in order to pass that info up to the top, I would set an instance variable in the object, right before you return false. Since the controller is still operating on the same object as the Observer, this same information is available.
... in your Observer model.is_valid = false # or_something_went_wrong = true, etc. return false
Then just operate on that accordingly in your Controller.
Upvotes: 0