How can I validate if the input in a text field is a number? not_integer is not what I am looking for. It can be a decimal number.
You can check for numericality
validates :points, numericality: true
If you want a more general approach, you can use is_a?. The parent number class in Ruby is Numeric.
a = 4
a.is_a? Numeric
=> true
b = 5.4
b.is_a? Numeric?
=> true
c = "apple"
c.is_a? Numeric
=> false
d = "4"
d.is_a? Numeric
=> false
To restrict the user from entering non-numeric values at the form-level and avoid expensive server call just to check numericality.
Use this in the form:
<%= f.number_field :attribute_name, :step => 'any' %>
This will create an html element as below:
<input id="post_attribute_name" name="post[attribute_name]" step="any" type="number">
Upon form submission, the input value is checked at the form level. step = "any" will allow decimals.
I would also recommend adding validation at the Model level using,
validates :attribute_name, numericality: true ## As suggested by Justin Wood
This way you have double protection, i.e., one at the form-level itself and the other at Model level.
Related
I am trying to validate the entry a user makes in an amount field.
The field is amount_money
This field is a string which is validated on form submission
monetize :amount, :as => :amount_money
validates :amount, numericality: {only_integer: true}
validates :amount_money, numericality: {greater_than_or_equal_to: 0}
validate :amount_money_within_limit
validate :is_a_valid_number
I want to ensure there are no letters or symbols and that the amount is in an acceptable range.
the code to do this is
def amount_money_within_limit
if amount_money && amount_money.cents > 10_000_00
errors.add(:amount_money, 'cannot exceed $10,000.')
end
if amount_money && amount_money.cents < 1_00
errors.add(:amount_money, 'Problem with Amount')
end
end
this works great for input numbers, of numbers and letters, of letters, of special characters but
If I try Bob - the validation kicks in
but if I try BBob - the validation is bypassed.
If the input contains 2 Capital letters next to each other - it fails.
I've tried a downcase - but that doesn't suit as the field is monetized (money gem) - and the downcase screws up if there is valid input.
If the input to the field contains two uppercase letters - all the validations are bypassed So something like AA is not caught by any on the above validations
Why don't you use regular expressions? Something like this:
def is_a_valid_number? amount_money
amount_money =~ /\d+/
end
It seems you have put 1 validation on the wrong field, you should've put validations only on amount field (your real db field), and not on the amount_money which is automagical field from rails-money gem. I'll apply their documentation on numerical validations to your case:
monetize :amount,
:numericality => {
:only_integer => true,
:greater_than_or_equal_to => 1_00,
:less_than_or_equal_to => 10_000_00
}
You won't need any other custom validations with this setup.
I'm trying to validate the format of a field in an ActiveRecord. I want this field to either be empty, or contain a sequence of digits only (it is containing an optional port number for a database connection). I'm currently trying this:
validates_format_of :port, with: /\A[0-9]*\Z/, message: 'Only numbers allowed'
but without luck. I've found that adding a required number by using for example {1, 6} sort of works, but makes the field mandatory.
Any advice?
Many thanks in advance,
Joseph.
If you're looking to validate so that only numbers are allowed, then you should be able to use this:
validates :port, :numericality => {:only_integer => true}
You may want to try to validate the numericality of the field, like so:
validates_numericality_of :port, :only_integer => true
:only_integer will ensure that the value entered for :port is an integer.
You can also just add allow_blank: true
You can use this syntax as well
validates numericality: :only_integer
I'm struggling to get a inclusion validation to work on a model so maybe some one could tell me what I'm missing here.
This is the model I have:
class Order < ActiveRecord::Base
ORDER_TYPES = %w{ Verkooporder Retourorder }
ORDER_TYPES.each_with_index do |meth, index|
define_method("#{meth}?") { type == index }
end
validates_inclusion_of :order_type, :in => %w{ Verkooporder Retourorder }
...
I also created a form that creates a dropdownbox using the constant array like this:
(I'm
= f.input :order_type, as: :select, collection: Order::ORDER_TYPES, label: 'Order type', include_blank: false
And I save it to my model like this:
#order.order_type = params[:order][:order_type]
So when I save my order model it always fails on validating the order_type.
Is there anybody who can point me out what I'm doing wrong?
PS: The order_type is an integer value field in my model.
The problem is that you are defining methods Verkooporder? and Retourorder?, but they're not being called from your validation because the :in is interpreting %w{ Verkooporder Retourorder} as an array of strings, i.e. [ "Verkooporder", "Retourorder"].
What you actually want to validate is that order_type is a number between 0 and the size of the ORDER_TYPES array, i.e. a string with a value between 0 and 1:
validates_inclusion_of :order_type, :in => %w{ 0 1 }
In this case you don't really need to define the boolean Verkooporder? and Retourorder? methods, unless you need them elsewhere.
UPDATE:
I realize now that your form will return order_type as a string in Order::ORDER_TYPES, which won't work with the validation above since the validation above is validating on integer-valued strings.
The way I've done this in the past is not to use an integer for order_type but a string. In that case, you can just validate with validates_inclusion_of :order_type, :in => ORDER_TYPES, and the select drop-down doesn't have to change. Is there any particular reason you're using an integer value field for order_type? Alternatively you could have the select return integer values for each order type.
I have a Price model with 4 different fields:
t.decimal "amount"
t.decimal "amount_per_unit"
t.decimal "unit_quantity"
t.string "unit"
I'm trying to make a custom validation that allows either the amount or amount_per_unit fields (this includes unit quantity and unit) to be filled but not both of them. So to make a word diagram of what I mean.
amount = YES
amount_per_unit + unit + unit_quantity = YES
amount_per_unit (alone or amount.present) = NO
unit_quantity (alone or amount.present) = NO
unit (alone or amount.present) = NO
amount and amount_per_unit + unit + unit_quantity = NO
if you still are confused, just know that its either the amount itself thats filled in or the amount per unit fields that are (1 or 3).
So far I tried this validation in my Price model:
validates :amount, :numericality => true
validates :amount_per_unit, :numericality => true
validates :unit_quantity, :numericality => true
validates :unit, :inclusion => UNITS
validate :must_be_base_cost_or_cost_per_unit
private
def must_be_base_cost_or_cost_per_unit
if self.amount.blank? and self.amount_per_unit.blank? and self.unit.blank? and self.unit_quantity
# one at least must be filled in, add a custom error message
errors.add(:amount, "The product must have a base price or a cost per unit.")
return false
elsif !self.amount.blank? and !self.amount_per_unit.blank? and !self.unit.blank? and !self.unit_quantity
# both can't be filled in, add custom error message
errors.add(:amount, "Cannot have both a base price and a cost per unit.")
return false
else
return true
end
end
This validation doesn't work though as all fields are blank it results to a numericality error and if I fill all of them, it creates the price with all fields filled. What needs to be fixed?
I think your values are coming in as nil, not blank.
Try changing the second condition to:
elsif !self.amount.to_s.blank? and !self.amount_per_unit.to_s.blank? and !self.unit.to_s.blank? and !self.unit_quantity.to_s.blank?
Also, it seems you have a typo on the last condition on both statements (e.g. !self.unit_quantity instead of !self.unit_quantity.to_s.blank?
I hope that helps.
This one fails when a zero is at the end
12.12 passes
5.51 passes
12.50 fails
12.60 fails
price_regex = /^\d+(\.\d{2})?$/
why? and how do I fix it?
Some more info
in _form.html.erb
<p>
<%= f.label :price %><br />
<%= f.text_field :price %>
</p>
in menu_item.rb
price_regex = /^\d+(\.\d{2})?$/
validates :price, :presence => true,
:format => { :with => price_regex }
in menu_items_controller.rb
def create
#menu_item = MenuItem.new(params[:menu_item])
if #menu_item.save
respond_with #menu_item, :location => menu_items_url
else
flash[:notice] = "Not Saved"
end
end
price is a decimal in the database with a precision of 2.
You say that price is "a decimal in the database with a precision of 2". That means that price is being represented as a BigDecimal in Ruby and the regex test will be done on the string form of that BigDecimal. A little bit of experimentation will clarify things:
> p = BigDecimal.new('12.50')
=> #<BigDecimal:12a579e98,'0.125E2',18(18)>
> p.to_s
=> "12.5"
And so your regex will fail. You shouldn't be using a regex for this at all, regexes are meant for strings but you're checking a number. You should be able to keep using your regex if you allow for the conversion:
/^\d+(\.\d{1,2})?$/
I'm using Rails 3 with the client_side_validations gem, which means I need a Regexp that works both in Ruby and Javascript. I also have a clear delineation between frontend and backend format--The user should never be able to enter "$12.5", but once it hits the server, I don't care about the trailing 0.
My solution was to add a core extension (in my case, for Float, but BigDecimal would probably be more appropriate in most cases):
class Float
def can_convert_to_i_with_no_loss_of_precision
(self % 1).zero?
end
alias_method :to_s_with_loss_of_trailing_zeroes, :to_s
def to_s
if can_convert_to_i_with_no_loss_of_precision
to_i.to_s
else
"#{to_s_with_loss_of_trailing_zeroes}#{0 if (self * 10 % 1).zero?}"
end
end
end
Now I can use this in a Model, and it plays nicely on the front end (Javascript doesn't convert it to a Float, so the user will always be forced to enter 2 digits after the decimal) and on the backend (where ActiveModel's FormatValidator will call to_s and the core extension will know when to add the trailing 0):
validates :price, :format => { :with => /^\d+(\.\d{2})?$/, :allow_blank => true }
The regex looks fine to me. I tested it at Rubular with the inputs you mentioned and a few more, and it captures all of them correctly.
The problem is likely with some other part of the code. Maybe you are using price = <regex>, whereas you should be using price =~ <regex> to match a string with a regex.