Rails range validation with data from another model - ruby-on-rails

I have a Ticket and Event model in which the relationship is that an Event has many Tickets. The Ticket model has columns serial starting value and serial ending value which denotes the range of the valid serial nubers for that event.
I want to validate the Ticket on creation so that if a Ticket is created with a serial number beyond that range, the system will spew out errors saying that the range in invalid.
What I currently have in my ticket model validation is another validation to show a valid serial number for all events which is between 140000 and 149999
validates :serial_number,
presence: true,
numericality: {
only_integer: true,
:greater_than_or_equal_to => 140000,
:less_than => 149999,
:message => "is invalid" },
:uniqueness => { :message => "%{value} has already been taken" }
I need to get data from the Event model and place it into the Ticket validation. Does Rails allow something like this in the model? Should I do it in the controller?

Definitely do this in your model. Use custom validations for it:
validate :serial_number_valid
def serial_number_valid
unless event.serial_number_range.include?(serial_number)
errors.add(:serial_number, "must be within range")
end
end

One way to do this is by using rails validation helper of inclusion. This helper validates that the attributes' values are included in a given set. For this particular case you can use:
validates :serial_number, inclusion: { in: 140000..149999 }, presence: true, uniqueness: true
If you want to use the same method in rails 4 way here's a link to that.

Related

Ruby - Checkbox Validation

I'm trying to get my checkbox validation working for my app. Basically, I enter a vehicle id number (VIN) and the system checks if there is a duplicate in the database. We want to allow the duplicate if the user clicks a checkbox to allow it. Here is my current code:
View:
.field-row
%label VIN
= f.text_field :vin, class:'mono-field'
.field-row
%label Allow Dup VIN
= f.check_box :vincheck
Model:
class Vehicle < ApplicationRecord
attr_accessor :vincheck
#this checks if the checkbox is checked
validates_acceptance_of :vincheck, message: "Must check 'Allow Dup Vin' to save a duplicate VIN."
#this checks for the duplicate VIN in the database
validates :vin, uniqueness: true, :if => :vincheck
If I enter a duplicate VIN and don't check the checkbox I get the following errors:
Vincheck Must check 'Allow Dup Vin' to save a duplicate VIN.
Vin has already been taken
If I enter a valid VIN I get:
Vincheck Must check 'Allow Dup Vin' to save a duplicate VIN.
If I enter a valid VIN and click the checkbox I don't get any errors. I need to be able to select the checkbox and leave a duplicate VIN in there.
I feel like I'm close but must be missing something. Its as if the
:if => :vincheck
isn't actually doing anything. I thought that would have allowed me to skip out on having the validates_acceptance_of.
Any thoughts?
thanks!
You're close, just use a Proc in your "if" clause:
validates :vin, uniqueness: true, :unless => Proc.new { |vehicle| vehicle.vincheck? }
The current record is passed to the Proc, so you can check any of the attributes.
You also don't need the acceptance validation for vincheck. That will force the box to be checked. You should use a custom message on the vin validation that explains the usage of the check box.
Here is how I finally got it working. I added vincheck into the database and preset the values to 1. Here is the code that does the check:
validates :vin, uniqueness: true, :unless => Proc.new { |vehicle| vehicle.vincheck == '1' }
Thanks to #Michael Chaney for the Proc and db suggestions.
You have added acceptance validation, due to which acceptance is get check each time, irrespective of vin number,
please try following solution, this will show acceptance error message only if vincheck id failed.
class Vehicle < ApplicationRecord
attr_accessor :vincheck
validates_acceptance_of :vincheck,
message: "Must check 'Allow Dup Vin' to save a duplicate VIN.",
:if => :vincheck_fail?
validates :vin, uniqueness: true, :unless => :vincheck
def vincheck_fail?
self.vin.present? && Vehicle.where('vin = ? AND id != ?', self.vin, self.id).present?
end
end
I hope this will work for you.

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.'}

Validation of fields from some box on the view - Rails

I have an User model. It has next fields:
attr_accessible :user_name, :first_name, :last_name, :email ....
There is a profile view for the User with 6 blocks. Each of them associated with the various fields. Box 1 - first_name and last_name, Box 2 - user_name and email, etc.
I need to validate all the fields (presence, format, etc). But validators must trigger only for those fields, that has came from a particular block (Box 1 or Box 2, for example).
If I write something like next:
validates :user_name, :presence => true
and I will not edit the block with the *user_name*, I will see the error "user Name can't be blank". I can't use *:allow_blank => true* or nil because it can't(!) be blank!
In two words: I must validate only those fields, that was past from the resquest.
What I can do to solve my problem? Thx
You can add if or unless option to skip of particular condition.
validates :user_name, :presence => true, :if => "first_name.blank? and last_name.blank?"
You can pull the specific fields out of your model and create a model for each block, then you add one_to_one relationships to your User model.

How do you scope uniquenuess based on two values with Rails 3 validations?

I have an model, called Replay, that has 3 attributes, match_id, game_number, and uploader_id. Essentially, I would like a validation to enforce that an uploader does not upload a replay for a match with the same game number as a replay they have already uploaded for that match. I would like, however, for another user to be able to upload a replay for that match and game number.
The validation I am using now is:
validates :game_number, presence: true, uniqueness: { scope: :match_id }
But this does not take into account the uploader_id. Any help would be appreciated.
Try this:
validates :game_number, presence: true, uniqueness: { scope: [:match_id, :uploader_id] }

preventing rails validation based on previous validation

I have a model with 2 validations on the 'name' attribute. It goes something like this:
validates :name, :uniqueness => true
validate do
errors.add(:name, "is dumb") if name_is_dumb?
end
I don't want the 2nd validation to run if the first validation fails (the name is not unique).
What's the best and cleanest way to do this?
According to the documentation:
Callbacks are generally run in the
order they are defined, with the
exception of callbacks defined as
methods on the model, which are called
last.
So the following snippet should work:
validates :name, :uniqueness => true
validate do
errors.add(:name, "is dumb") unless errors[:name].nil?
end

Resources