Rails model passes validation but view still renders errors?
Oddly enough, my model passes validation just fine, and acts as expected, however I still have the error rendered to the view.
# Controller
def up
@vote = Vote.create :vote => true, :voter => current_user, :voteable => Recipe.find(params[:id])
respond_to do |format|
format.js { render :json => {:model => 'vote', :success => @vote.valid?, :errors => @vote.errors }}
end
@vote.errors.clear # <= doesn't seem to help
end
The model I wrote has a custom validation:
c开发者_JS百科lass Vote < ActiveRecord::Base
# ... associations etc.
validate :voter_voting_too_frequently?
private
def voter_voting_too_frequently?
last_vote_cast_by_voter = Vote.find_last_by_voter_id self.voter
unless last_vote_cast_by_voter.nil? || last_vote_cast_by_voter.created_at < 5.seconds.ago
errors.add_to_base("You can only vote every 5 seconds.")
end
end
end
And lastly, the response that is rendered to the view: (returned as js no doubt, but would be the same if it were in a <div>
)
{"errors":[["base","You can only vote every 5 seconds."]],"model":"vote","success":false}
And even though it was successful, this is continuously returned.
Ideas on how to debug this?
The issue was totally bizarre, and was related to render => :json
. Strangely the :success
key couldn’t be first in the hash, when the respond_to
block renders json.
This was the only change that needed to be changed:
format.js { render :json => {:model => 'vote', :errors => @vote.errors.on_base, :success => @vote.errors.on_base.nil?} }
Also I'm logging a ticket with the rails team.
It doesn't look like it is passing the validation since the success status is false.
If you take a look at you custom validation it seems that the "unless" keyword has caused some confusion.
Try:
if !last_vote_cast_by_voter.nil? && last_vote_cast_by_voter.created_at < 5.seconds.ago
errors.add_to_base ...
I think your unless
statement is wrong. Personally I am not used to them, so I always rewrite to if statements
if last_vote_cast_by_voter.nil? == false && last_vote_cast_by_voter.created_at > 5.seconds.ago
Looking at this line, I would suspect that last_vote_cast_by_voter.created_at
should be lower than 5 seconds, therefore I suppose your unless statement should be changed into
unless last_vote_cast_by_voter.nil? || last_vote_cast_by_voter.created_at > 5.seconds.ago
Adding @vote.errors.clear
indeed does not help, since the view is rendered at the point already...
If this still is not working try to write a test where you cast some votes. The time between two votes should be 1 second and 10 seconds for example.
Check if Vote.find_last_by_voter_id
is working properly.
If all these test are working and rendering your view is not, then something strange is going on in your view and you should post some more information about your view, I guess.
精彩评论