Rails custom validation message with helper method - ruby-on-rails

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.

Related

How do I access validates_format_of in Activerecord::Validator?

I'm trying to use validates_format_of getting a nomethod error. I think it's because I'm using "class [nameofclass] < ActiveRecord::Validator" and Validator lacks this method.
I need to include something or use another inherit and I don't know how to do this.
codesource: https://github.com/sidhene/WebsiteOne/commit/7621a89300134f3899537ab5f35c2fa33d723b61
validates_format_of does not work this way , it is meant to create hooks on the database record and run validations before the database record is saved. It does not work as a method on an instance of a class.
What you could do is instead use the regular expression you created and add that to your conditional:
validation_regex = %r{\.(png|jpg|jpeg)$}i
if record.image_url.present?
unless is_whitelisted?(record.image_url) ||
validation_regex.match(record.image_url?)
record.errors[:image_url] = 'Invalid image url. Image provider not found in provider whitelist.'
end
end

Rails: Custom Model Validation

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

Devise: => #<NoMethodError: undefined method `downcase!' for 1:Fixnum>

This may or may not be a devise error, but I think it is.
In testing I tried assigning an integer as the email address. I am getting this error from the 'bowels' of active record save:
=> #<NoMethodError: undefined method `downcase!' for 1:Fixnum>
This is despite the fact that I have this validation on my User < ActiveRecord::Base.
validates :email, format: { with: /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i, message: "Invalid email"}
I am guessing that somehow some devise validation or other hook is being called on the email address and blowing up. What can I try next?
Have a look at the Devise sourcecode:
The authenticable module adds before_validation :downcase_keys, which does the following:
def downcase_keys
self.class.case_insensitive_keys.each { |k| apply_to_attribute_or_variable(k, :downcase!) }
end
(see lib/devise/models/authenticatable.rb for reference)
It is used to downcase all case insensitive keys before applying any logic to the models. By default configuration provided by Devise, case_insensitive_keys contains the email field you are setting with a Fixnum.
# Keys that should be case-insensitive.
mattr_accessor :case_insensitive_keys
##case_insensitive_keys = [ :email ]
(see lib/devise.rb for reference)
This way, the validation is executed even before your own validation is checked. Perhaps an additional verification for the variable's type could be added to Devise, but by default you'll only assign a String provided by the login / etc. form to that field.
I hope i could clarify this a bit.

Better error handling than what I am currently doing?

I needed an error object to pass errors between controllers and js views for ajax responses. I wanted to use ActiveModel::Errors since then I could easily merge errors from model validation to non-model errors. But Ive been having some problems using this approach.
Using ActiveModel::Errors.new(nil)
If I try and call to_a() like so:
#errors = ActiveModel::Errors.new(nil)
#errors[:test] = "is a required field."
#errors.to_a().join("<br />")
I get the error:
undefined method `human_attribute_name' for NilClass:Class
Its trying to call the human_attribute_name for the nil I passed into Errors.new which is suppose to be a ActiveRecord Model.
I am wondering if anyone knows of a better way to handle errors or if the approach I am taken has already been made into some gem.
Chances are your validations are related to "something" that could be encapsulated in a model - it just doesn't need to be an ActiveRecord model.
You can use validations in any plain ruby object by doing something like this:
require 'active_model'
class Band
include ActiveModel::Validations
validates_presence_of :name
attr_accessor :name
end
Then, the usual suspects would work just fine:
b = Band.new
b.valid?
#false
b.name = "Machine Head"
b.valid?
#true

calling custom validation methods in Rails

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")

Resources