I want to check an integer value in validation. But I want to do it depending on the value of another field. For example, if the width value exists, let it be at least 300 if the width_type is "px", but 30 if the width_type is "rate". How can I do it thanks.
If I understand correctly you are looking for conditional validation
In that case the following should work:
validates :width, numericality: { only_integer: true}
validates :width, numericality: { greater_than_or_equal_to: 300}, if: -> {width_type.to_s == 'px'}
validates :width, numericality: { greater_than_or_equal_to: 30}, if: -> {width_type.to_s == 'rate'}
If you need to handle too many other scenarios I would go with a custom validation like
MIN_WIDTH_PER_TYPE = {px: 300, rate: 30}
validates :width, numericality: { only_integer: true}
validate :_width_with_type
private
def _width_with_type
min_width = MIN_WIDTH_PER_TYPE[width_type.to_sym]
if width < min_width
errors.add(:width, "must be at least #{min_width} when using width type '#{width_type}'")
end
end
You could clean this up further as well but this should point you in the right direction.
Related
I don't understand why I can't use self here?
class PayoutRequest < ApplicationRecord
validates :phone, confirmation: true, on: :create
validates :phone_confirmation, presence: true, on: :create
belongs_to :user, foreign_key: "user_id"
validates :amount, numericality: { only_integer: true, greater_than_or_equal_to: 300, smaller_than_or_equal: self.user.balance }
scope :paid, -> { where(:paid => true) }
scope :unpaid, -> { where(:paid => false) }
end
How can I write this?
Use a custom method, for example:
validate :amount_not_greater_than_balance
def amount_not_greater_than_balance
return if amount <= user.balance
errors.add(:amount, "can't be greater than balance")
end
In addition, you should probably only run this specific validation rule on: :create -- because it would presumably be totally acceptable for a payment request to become more than the user's balance, later on n the future.
Because self is not what you think it is. In case you didn't know or forgot, validation DSL is just methods called on the class itself. Here you basically call PayoutRequest.validates and pass it some parameters.
validates :amount, numericality: { only_integer: true, greater_than_or_equal_to: 300, smaller_than_or_equal: self.user.balance }
^ ^ arg ^ kw arg ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
method name just a regular hash, defined at the class level. So `self` is the class.
I am trying to make sure that users have a valid graduation date within my application. Not sure if my variable for the current_year will be updated every time I want to validate a user's graduation date. Here is what I have (I am making this field optional for users):
current_year = Time.now.year
if !(:grad_year.nil?)
validates :grad_year, numericality: { greater_than_or_equal_to: current_year, less_than_or_equal_to: current_year + 5 }
end
validates :grad_year, numericality: { greater_than_or_equal_to: Date.today.year, less_than_or_equal_to: Date.today.year + 5 }, allow_nil: true
Actually, it is not correct to use Date.today.year for validation because the current year will be hardcoded on Rails start and won't update next year (until you restart Rails).
Use Lambda instead:
validates :grad_year, numericality: { greater_than_or_equal_to: -> { Date.today.year }, less_than_or_equal_to: -> { Date.today.year + 5 } }, allow_nil: true
In one of my rails models I have this :only_integer validation:
validates :number, presence: true, numericality: { only_integer: true }
This validation also allows inputs like +82938434 with +-signs.
Which validation should I use to only allow inputs without + - only numbers?
The documentation for only_integer mentions this regex :
/\A[+-]?\d+\z/
It means you could just use:
validates :number, format: { with: /\A\d+\z/, message: "Integer only. No sign allowed." }
Rails 7 added :only_numeric option to numericality validator
validates :age, numericality: { only_numeric: true }
User.create(age: "30") # failure
User.create(age: 30) # success
In my current Rails project, I have a model called "Child," with two parameters, "choc_cupcake" and "cherry_cupcake."
Each child should be allowed to have up to 5 cupcakes total, in any combination of chocolate and/or cherry cupcakes. So far, my model validation code just allows each child to have up to 5 chocolate cupcakes AND up to 5 cherry cupcakes.
class Child < ActiveRecord::Base
validates :choc_cupcake, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 5 }
validates :cherry_cupcake, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 5 }
end
Is there a way to specify that if a child chooses X chocolate cupcakes, then he/she can have no more than (5-X) cherry cupcakes? Something like this, maybe?
validates :cherry_cupcake, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: (5 - :choc_cake) }
class Child < ActiveRecord::Base
validates :choc_cupcake, numericality: { only_integer: true, greater_than_or_equal_to: 0}
validates :cherry_cupcake, numericality: { only_integer: true, greater_than_or_equal_to: 0}
validate :no_more_than_5_total_cupcakes
private
def no_more_than_5_total_cupcakes
if (choc_cupcake + cherry_cupcake) > 5
message = "No more than 5 total cupcakes!"
errors.add(choc_cupcake: message)
errors.add(cherry_cupcake: message)
end
end
end
I have a model and adding some validations
This is what I originally had:
validates :speed,
allow_blank: true,
numericality: { only_integer: true, greater_than: 0 }
But I keep getting errors when importing items from my CSV file stating that
Speed must be an integer
I then changed it to:
validates :speed,
numericality: { only_integer: true, greater_than: 0 }, unless: "speed.nil?"
But I get the same errors here too.
Basically I want it to validate that speed is numeric and greater than 1 unless no speed is passed in and to allow that blank value.
Any ideas?
CSV Importer:
def self.import_from_csv(file)
Coaster.destroy_all
csv_file = CSV.parse(
File.read(
file.tempfile,
{encoding: 'UTF-8'}
),
headers: true,
header_converters: :symbol
)
csv_file.each do |row|
coaster_name = row[:name]
# No need to keep track of coasters already in the database as the CSV only lists each coaster once unlike parks
# create the new coaster
park = Park.find_by_name_and_location_1(row[:park], row[:location_1])
manufacturer = Manufacturer.find_by_name(row[:manufacturer])
coaster = Coaster.create!({
name: row[:name],
height: row[:height],
speed: row[:speed],
length: row[:length],
inversions: row[:inversions] == nil ? 0 : row[:inversions],
material: (row[:material].downcase if row[:material]),
lat: row[:coaster_lat],
lng: row[:coaster_lng],
park_id: park.id,
notes: row[:notes],
powered: row[:powered],
manufacturer_id: (manufacturer.id if manufacturer),
covering: row[:covering],
ride_style: row[:ride_style],
model: row[:model],
layout: row[:layout],
dates_ridden: row[:dates_ridden],
times_ridden: row[:times_ridden],
order: row[:order],
on_ride_photo: row[:on_ride_photo] == 1 ? true : false,
powered: row[:powered] == 1 ? true : false
})
ap "Created #{row[:name]} at #{row[:park]}"
end
end
I think the value for speed from csv is interpreted as string. You may use .to_i with that specific value that you are using for speed. Change your code like this:
park = Park.find_by_name_and_location_1(row[:park], row[:location_1])
manufacturer = Manufacturer.find_by_name(row[:manufacturer])
row_speed = row[:speed].blank? ? nil : row[:speed].to_i
coaster = Coaster.create!({
.....
speed: row_speed,
.....
})
And then in validation:
validates :speed, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true
Validations accept an :allow_nil argument, as noted here in the Rails guides: http://edgeguides.rubyonrails.org/active_record_validations.html#allow-nil
If the attribute is nil when :allow_nil is true, that particular validation will only run if the attribute in question is present.
I think, validates numericality accepts allow_nil attribute. Try this:
validates :speed, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true