Reputation:
I'm using the gem Responders but I'm not able to show errors that I create on my models using erros.add(:base, 'Error message')
.
On my controller, before the respond_with @app
, I debugged the @app
object and it has errors @app.errors.any?
returns true
On my view, when I check the flash
and @app
objects, none has the error
App controller
# app_controllers.rb
def destroy
@app = current_company.apps.find(params[:id])
@app.destroy
respond_with @app
end
App model
# app.rb
before_destroy :destroy_on_riak
# ...
def destroy_on_riak
# SOME CODE HERE
rescue Exception => e
errors.add(:base, I18n.t("models.app.could_not_destroy", :message => e.message))
return false
end
App view
# apps.html.haml
-flash.each do |name, msg|
%div{:class => "flash #{name}"}
=content_tag :p, msg if msg.is_a?(String)
This is the @app object before the @app.destroy
"#<ActiveModel::Errors:0x00000004fa0510 @base=#<App id: 34, ...>, @messages={}>"
This is the @app object after the @app.destroy
"#<ActiveModel::Errors:0x00000004fa0510 @base=#<App id: 34, ...>, @messages={:base=>[\"Não foi possível excluir a aplicação: undefined method `get_or_new' for #<App:0x00000004f824c0>\"]}>"
I have removed what's inside the @base=
for simplicity.
Upvotes: 0
Views: 928
Reputation: 21
jefflunt is correct, when one calls #valid?
it clears the errors array: see https://github.com/rails/rails/blob/4a19b3dea650351aa20d0cad64bf2d5608023a33/activemodel/lib/active_model/validations.rb#L333
The validators are designed to 100% determine the validity of your object, not when you add errors yourself for later use.
While ActiveRecord does override #valid?
, it still calls super
: https://github.com/rails/rails/blob/4a19b3dea650351aa20d0cad64bf2d5608023a33/activerecord/lib/active_record/validations.rb#L58
If you want to add errors and have them persist I recommend something like this:
def failures
@failures ||= []
end
validate :copy_failures_to_errors
def copy_failures_to_errors
@failures.each { |f| errors.add(*f) }
end
Then modify your rescue
:
def destroy_on_riak
# SOME CODE HERE
rescue Exception => e
failures.push([:base, I18n.t("models.app.could_not_destroy", :message => e.message)])
return false
end
I know this seems convoluted and I know there are even examples online where people use or recommend errors.add(:base, ...)
, but it is not a safe way to store and retrieve errors for later.
Also, just a recommendation, but I advise you to rescue StandardError
and not Exception
unless you absolutely must. Out of memory errors and stuff like that are Exception
s, but every normal error you would ever want to rescue should inherit from StandardError
. Just FYI.
Upvotes: 2
Reputation: 2208
I'd have to agree with @p.mastinopoulos on this. This should really be handled with the builtin validations. Sounds like you are in need of building a custom validator.
http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validate
Try replacing your before_destroy
with a validate
:
validate :destroy_on_riak, on: :destroy
Haven't tried this, but if it doesn't work, you may want to consider creating a custom Validator as referenced in the docs.
Upvotes: 0
Reputation: 7810
I will give you some hints:
Hint 1
Your form may be calling valid?
on the @app
object. The valid?
method clears the errors
array on the instance.
It is not correct to use the errors
array/construct outside of the validations context. But this is MHO.
Hint 2
According to Responders gem (which I have never used in the past), your locale just needs to have the correct configuration. Example:
flash:
actions:
create:
notice: "{resource_name} was successfully created"
update:
notice: "{resource_name} was successfully updated"
destroy:
notice: "{resource_name} was successfully destroyed"
alert: "{resource_name} could not be destroyed"
Does it?
Upvotes: 1
Reputation: 33954
The mystery seems to be either (a) you might not be calling the right method, or (b) the .errors
hash doesn't contain what you think it contains.
In your controller you're calling @app.destroy
, but the method that adds the errors is called destroy_on_riak
Are you sure you don't mean to type this?
# app_controllers.rb
def destroy
@app = current_company.apps.find(params[:id])
@app.destroy_on_riak # <= The offending line?
respond_with @app
end
Or is there a before_destroy
callback missing from your code sample that in turn calls destroy_on_riak
? From the code included I don't see anywhere that the destroy_on_riak
method ever gets called, so this is just a guess.
.errors
hash?If that's not the problem, then when @app.errors.any?
is returning true
, then at that point in the code print the contents of @app.errors
to your log so you can see what's wrong.
Upvotes: 1