Hi I am trying to write a custom validation for a model that does not allow the model to be saved if it fails the validation.
Here is what I have so far:
validate :valid_est_time
private
def valid_est_time
if !self.est_time.is_a? Integer || self.est_time >= 0
self.errors.add("Invalid Response Estimated Time.")
end
end
The validation works by not saving the model, but it also throws an error (which I dont want it to do)
NoMethodError in Jobs#index
Showing /Users/squitorio/Documents/Project/Dispatcher/assist/app/views/jobs/_index_active.html.erb where line #19 raised:
undefined method `minutes' for nil:NilClass
I just want it to not save the model, and carry on
You can use the before_save callback. If you return false from any of the methods called before_save it cancels all the subsequent callbacks. This will stop your model from saving. Have a look at this http://guides.rubyonrails.org/active_record_callbacks.html
If you still want to use other features of Rails validation then take a look at custom validations here http://guides.rubyonrails.org/active_record_validations.html#performing-custom-validations
Related
Failed to replace tickets because one or more of the new records could
not be saved.
My Form model has_many tickets. A ticket cannot have a form if it has a particular flag set. When i go to test this by trying to assign a ticket to an existing form, it crashes rather than pay attention to my validations.
Since its RailsAdmin, I see its just calling update_attribute (which apparently saves nested objects) before doing the error handing of checking if the Form object saves or not.
Is there any known way to get RailAdmin to gracefully catch this validation exception long enough to do its normal error handling for the Form itself failing validation? It's all part of the automatic stuff handling edits/new of an arbitrary object.
I'm using Rails 4.2.0 and RailsAdmin 1.1.1
Edit for Guilermo:
I have models on rails admin that fail to save because the nested object was invalid. Are you using the nested form field on rails admin? Could you show the rails admin configuration code on the form model and the validation? I'd be happy to help with that.
Whoever created this code used simple default things, the following is the relevant line inside the RailsAdmin config initializer.
edit do
include_all_fields
end
Observed behavior is the standard RailsAdmin field where you can search for objects, or pick from a drop down, and select one or more of them to be attached to the current object.
The nested object IS invalid (and as a result the parent object is as well). The problem is that rather than returning the parent object as invalid, the system crashes because the nested object is invalid.
The RailsAdmin code appears to call update_attribute (which throws an uncaught error), and then actually does the save! (along with crash check). I am basing this on the following code:
https://github.com/sferik/rails_admin/blob/master/lib/rails_admin/config/actions/edit.rb
Specifically:
#object.set_attributes(params[#abstract_model.param_key])
#authorization_adapter && #authorization_adapter.attributes_for(:update, #abstract_model).each do |name, value|
#object.send("#{name}=", value)
end
changes = #object.changes
if #object.save
#auditing_adapter && #auditing_adapter.update_object(#object, #abstract_model, _current_user, changes)
respond_to do |format|
format.html { redirect_to_on_success }
format.js { render json: {id: #object.id.to_s, label: #model_config.with(object: #object).object_label} }
end
else
handle_save_error :edit
end
It crashes at #object.set_attributes.
You could avoid this problem by not showing the tickets that do not have that flag on your model edit form.
You can do this like this:
edit do
field :tickets do
associated_collection_scope do
proc { |scope| scope.where(flag: false) }
end
end
end
Unfortunately this means that you'll have to specify which fields will be shown and you won't be able to use
include_all_fields
You could use the include_fields method for a nicer syntax to do that
include_fields [:tickets, :other_field, :etc]
How can add the error message into #errors on controller then show it on the view like:
<%= #question.errors[:tag][0] %>
with tag is not model element.
Take a look at this part of the Rails validation guide. They work by creating a custom validator, which just appends the desired error message to the desired hash entry.
In your case, this might look like:
class Question < ActiveRecord::Base
validates_with :tag_validator
end
class TagValidator < ActiveModel::Validator
def validate(question)
unless question.special?
question.errors[:tag] << 'Not special enough.'
end
end
end
Working with error messages in rails is done in 3 steps viz.
Validating the active record object using rails-validation-helpers OR creating a custom validator as specified by #chaleyc
Validating the ActiveRecord(AR) object using AR validation methods
Showing the errors on views, creating a view helper is the best practice notices and errors on rails3
Here's a nice rails-cast to get you started
hi all what i am trying to do is create a "soft" validation in other words instead of my failing the validation and not saving the data to the DB, id like to have the validation give a warning to the user and allow the user to save faulty data if they so choose. but the validator will give them a warning before.
i want to do somehting like the following:
class MyModel < ActiveRecord::Base
warnings do
validate :warnings_validation
end
def warnings_validation
warnings.add(:name_of_element, "warning message") unless x == x
end
end
my model uses alot of inheritance and so gems like validations_scope dont work any ideas what i can do/use ?
I believe you could inspire yourself from the ActiveModel::Error example to implement the warning feature.
Explanation :
If you look at how the data is validated in Active Record, simply take a look at the valid? method :
def valid?(context = nil)
context ||= default_validation_context
output = super(context)
errors.empty? && output
end
The context and the output is not important, what matter is that the valid? method check if the errors instance variable is empty or not.
In other words, in the previous link I gave you, simply renaming the errors instance variable into warnings should do the trick. You'd have to create a custom validator using rails built-in and then simply call warnings.add(:name, "error") when needed. It should save the records while populating the warnings variable.
see this - custom validation
try this
validate :warnings_validation
def warnings_validation
self.name_of_element.blank?
errors.add(:name_of_element, "warning message") unless x == x
end
end
I'm trying to give a custom validation message to a uniqueness validation. However, for the error message I need slightly complicated behavior, so I'm putting this logic in a private method (error_message_for_email_uniqueness).
Here's the code I'm using
validates_uniqueness_of :email, message: error_message_for_email_uniqueness
Here's the error I'm getting
/Users/dylandrop/.rvm/gems/ruby-1.9.2-p290/gems/attr_encrypted-1.2.0/lib/attr_encrypted.rb:229:in `method_missing': undefined local variable or method `error_message_for_email_uniqueness' for #<Class:0x00000103684198> (NameError)
I've tried using message: lambda { error_message_for_email_uniqueness }, which also doesn't work. Also, I've tried wrapping it in a Proc instead of a lambda, which doesn't get me anywhere.
How can I get around this?
Did you define error_message_for_email_uniqueness as a class method?
I did a quick test, and this works fine:
validates_uniqueness_of :email, message: Proc.new { error_message_for_email_uniqueness }
def self.error_message_for_email_uniqueness
# logic to generate message goes here
end
If you want to create messages dynamically based on model attributes or something, you should create custom validator, because message is expected to be string.
I just upgraded my rails to 2.3.4 and I noticed this with validations:
Lets say I have a simple model Company which has a name. nothing to it.
I want to run my own validation:
class Company < ActiveRecord::Base
validate :something
def something
false
end
end
saving the model actually works in this case.
The same thing happens if i override validate() and return false.
I noticed this in a more complex model where my validation was returning false, but the object was still saving...I tried it out in an essentially empty model and the same thing applied. Is there a new practice I am missing? This doesn't seem to be the case in some of my older rails code.
Your validations are executed when you use the validate method. However rails doesn't relies on the returned value.
It relies on if there are validations errors or not. So you should add errors when your model doesn't validates.
def something
errors.add(:field, 'error message')
end
Or, if the error is not related to a field :
def something
errors.add(:base, 'error message')
end
Then your model won't be saved because there are errors.
You're getting confused between validations and callbacks.
Validations are supposed to fail if there are any errors on the object, doesn't matter what the validation returns. Callbacks fail if they return false, regardless if they add any errors to object.
Rails uses calls valid? from save calls which does not check the result of any validations.
Edit: Rails treats validate :method as a callback, but valid? still doesn't check for their results, only for errors they added to the object.
I don't think this behaviour changed at all but I could be wrong. I don't think I've ever written a validation to return false before.
Just FYI errors.add_to_base('error message') has been deprecated in rails 3 and got replaced by
errors[:base] << "Error message"
Or
errors.add(:base, "Error message")