"You need to supply at least one validation" but Rails validation exists - ruby-on-rails

I have the following validation:
class Event < ActiveRecord::Base
attr_accessible :starts, :ends
validates :no_multi_day_events
private
def no_multi_day_events
if (ends.day != starts.day)
errors.add(:ends, "No multi-day events")
end
end
end
However, when I try to load a page with this text, I get an error: You need to supply at least one validation
How do I supply the validation?

You should be calling:
validate :no_multi_day_events
and not
validates :no_multi_day_events

Related

Accessing model variable in validates, format

I have the (simplified) model structure below:
class Customer < ApplicationRecord
validates :full_name, format: { without: /[^a-zA-Z .,']+/, message: "cannot contain " + /[^a-zA-Z .,']+/.match(self.full_name).to_s}
end
I want to validate the user-provided full_name with a regular-expression and if the validation fails, I want to show which part of the full_name fails the regular-expression validation.
However, this returns "undefined method full_name" and I tried a bunch of other things for self.full_name but can't seem to figure out how to pass that data there.
How can I do this? Thanks for any feedback and answer, in advance.
According to the docs, Rails allows to pass a Proc message. Thus, in your case it's possible to customise the message:
class Customer < ApplicationRecord
validates :full_name,
format: {
without: /[^a-zA-Z .,']+/,
message: ->(object, data) do
"cannot contain " + /[^a-zA-Z .,']+/.match(object.full_name).to_s
end
}
end

How to set the order of validation methods ruby on rails?

I am a Ror beginner. There is a model Lecture, I want to validate the format of start time and end time firstly, and then check if the end time is after start time. It works well when the format is valid but once the format is wrong it comes with: undefined method `<' for nil:NilClass. How to makes start_must_be_before_end_time triggered only when the format is valid? Thanks!
Here is the code:
class Lecture < ActiveRecord::Base
belongs_to :day
belongs_to :speaker
validates :title, :position, presence: true
validates :start_time, format: { with: /([01][0-9]|2[0-3]):([0-5][0-9])/,
message: "Incorrect time format" }
validates :end_time, format: { with: /([01][0-9]|2[0-3]):([0-5][0-9])/,
message: "Incorrect time format" }
validate :start_must_be_before_end_time
private
def start_must_be_before_end_time
errors.add(:end_time, "is before Start time") unless start_time < end_time
end
end
There are no guarantees on the order of validations that are defined by validates methods. But, the order is guaranteed for custom validators that are defined with validate method.
From docs:
You can pass more than one symbol for each class method and the respective validations will be run in the same order as they were registered.
Alternatively
You can only run your validation method if all other validations pass:
validate :start_must_be_before_end_time, :unless => Proc.new { |obj| obj.times_valid? }
# Then, define `times_valid?` method and check that start_time and end_time are valid
You can go another way:
errors.add(:end_time, "is before Start time") unless start_time.nil? || end_time.nil? || start_time < end_time

Use value in override error message in Rails 4 for custom Validator

I am on Rails 4.2 I have written a custom Validator which will check if a value being entered exists in another table. I have been reviewing some other posts and it seems there is either a context specific or rails version preferred way to reuse the value being validated. In the rails docs i see examples such as:
validates :subdomain, exclusion: { in: %w(www us ca jp),
message: "%{value} is reserved." }
however, if I try to use %{value} in my custom message override it does not interpolate, but just prints "%{value}". I have seen various ways of calling "value". I also could not get %{value} to work in my Validator definition, but could get #{value} to work (New to ruby, if#{value} getting it from validate_each?).
I have also been struggling with various formats of the validation statement and putting in the custom message. Some things which look repeatable from the docs are not. If the way I am declaring my custom message is causing the error, please let me know how to correct?
class ExistingGroupValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless Group.where(:code => value).any?
record.errors[attribute] << (options[:message] || "#{value} is not a valid
group code")
end
end
end
class Example < ActiveRecord::Base
validates :group_code, presence: true
validates :group_code, :existing_group => {:message => "The code you have enterd ( **what goes here?** ) is not a valid code, please check with your teacher or group
leader for the correct code." }
end
Rails automatically puts the value at the beginning of the phrase, so you can just do this:
class ExistingGroupValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless Group.where(code: value).any?
record.errors[attribute] << (options[:message] || 'is not a valid group code')
end
end
end
class Example < ActiveRecord::Base
validates :group_code, presence: true
validates :group_code, existing_group: {message: 'is not a valid code, please check with your teacher or group leader for the correct code.' }
end
Separately, note that it is always "#{1+1}" to interpolate not %.
Rails is using Internationalization style string interpolation to add the value to the message. You can use the I18n.interpolate method to accomplish this. Something like this should do the trick:
class ExistingGroupValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless Group.where(:code => value).any?
record.errors[attribute] << (I18n.interpolate(options[:message], {value: value}) || "is not a valid group code")
end
end
end
class Example < ActiveRecord::Base
validates :group_code, presence: true
validates :group_code, :existing_group => {:message => "The code you have entered, "%{value}", is not a valid code, please check with your teacher or group leader for the correct code." }
end

Custom Validations Rails Model

I have a contact form and would like to show individual messages depending on what has failed.I would like to use flash messages. So from what i have read so far i can create a custom method (or i think it just overrides the one in place?)
So for example, i want to validate the presence of the name field
Class Message
attr_accessor :name
validates :name, :presence => true
def validate
if self.name < 0
errors.add(:name, "Name cannot be blank")
end
end
end
Within my controller i normally use a generic message
flash.now.alert = "Please Ensure all Fields are filled in"
Is there a way to call the particular message that failed validation?
Thanks
There is a plugin available, u can follow the below url
https://github.com/jeremydurham/custom-err-msg
Check the method validates because you can pass a message argument with the desired message.
validates :name, :presence => {:message => 'The name can't be blank.'}

How do I set a Rails validation to ensure that two attributes can't have the same value?

I have a form on my site that lets users direct a message at other users, but I want to ensure that they can't direct a message at themselves.
The class has attributes :username and :target_user, and I just want to set a validation that checks to make sure that these attributes can't have the same value, before anything gets saved.
I figured it would look something like this:
validates_presence_of :user_id, :username, :target_user, :message, :tag
validate :username != :target_user
But clearly don't know enough Ruby to do it correctly.
Up at the top with your validations:
validate :username_does_not_equal_target
and then a private/protected method within your model code:
def username_does_not_equal_target
#errors.add(:base, "The username should not be the same as the target user") if self.username == self.target_user
end
OR to attach the error to a specific attribute:
def username_does_not_equal_target
#errors.add(:username, "should not be the same as the target user") if self.username == self.target_user
end
You can change the text of your error message or the name of your method.
to read more on errors: http://api.rubyonrails.org/classes/ActiveRecord/Errors.html
to read more on validations: http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html
I hope this helps, happy coding!
Use validate
def validate
if self.username == self.target_user
self.errors.add :base, "You can't send message to yourself."
end
end

Resources