Reputation:
What I am trying to do is return an error, instead of an exception, when a particular model cannot be destroyed. Currently, it raises ActiveRecord::DeleteRestrictionError
, but that is not returned to a flash message, or added to the errors collection of the model.
What I have done is setup this in my resourceful controller:
def destroy
begin
resource.destroy
rescue ActiveRecord::DeleteRestrictionError => e
resource.errors.add(:base, e)
end
end
I'd rather not manage this within every single controller which requires this particular behavior. How can I abstract it? I can't see it being a good idea to overwrite the destroy method for ActiveRecord::Base
, but maybe there won't be any gotchas?
I'm using inherited_resources gem, so perhaps there is a way to answer this by extending that?
One other idea I had was to extend ActiveRecord::Base
using ActiveSupport::Concern
(from here: Rails extending ActiveRecord::Base) and then delegate the destroy method to a custom destroy on a model-to-model basis. Thoughts?
Upvotes: 1
Views: 923
Reputation:
What I ended up doing was inheriting my controllers from a master resources controller, which I've found to be much cleaner and powerful than the other options discussed (found here: http://roberto.peakhut.com/2010/09/27/admin-controllers-with-inherited-resources/).
// controllers/resources_controller.rb
class ResourcesController < ApplicationController
load_and_authorize_resource
inherit_resources
def destroy
begin
resource.destroy
rescue ActiveRecord::DeleteRestrictionError => e
resource.errors.add(:base, e)
end
end
end
Then, simply inherit your resourceful controllers from this controller instead of ApplicationController:
// controllers/models_controller.rb
class ModelsController < ResourcesController
end
Hope that helps somebody in a similar situation.
Upvotes: 0
Reputation: 15788
First I will say I agree with the attitude of not overriding ActiveRecord::Base methods like destroy. In order to DRY this behavior you have several options, I'll list two of them:
The first - Instead of writing the rescue clause in the specific controller you can embed it into your ApplicationController so the behavior will be application-wide:
# ApplicationController.rb
rescue_from ActiveRecord::DeleteRestrictionError do |exception|
resource.errors.add(:base, exception) if resource
end
Another option would be to make a module and include it in the different controllers you want to have this behavoir:
module SafeDestroyer
def safe_destroy(resource)
begin
resource.destroy
rescue ActiveRecord::DeleteRestrictionError => e
resource.errors.add(:base, e)
end
end
end
class MyController < ApplicationController
include SafeDestroyer
def destroy
safe_destroy(resource)
end
end
Upvotes: 2