rails length validation exception - ruby-on-rails-3

It is possible have in model for example user model
class User < ActiveRecord::Base
attr_accessible :number
validates_length_of :number, :is => 4
...
end
validation on length 4 (1234) with one exception that number can be value 0 ? :-)
i was looking to documentation here http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html but i dont know how to do it ?
edit: now i realized that maybe regexp can be used, but thats not my strong field :-p

You probably want to allow length of zero to prepare for the case the input is nil or blank.
There is built-in simple solution for such case
validates :number, length { :is => 4 }, allow_blank: true
# allow_blank includes cases of both nil and blank
Done.
Doc: http://guides.rubyonrails.org/active_record_validations.html#allow-blank

If the number comes in as a string you can validate the format of it with a regex to achieve something close:
class User < ActiveRecord::Base
attr_accessible :number
validates :number, :format => { :with => /^(\d{4}|0{1})$/ }
...
end
This says to validate the format of the number (assuming it is a string) such that from the beginning of the string there is either a pattern of 4 digits or a single 0 digit followed by the end of the string.

Related

Rails 3 Validation on Uniqueness - logic

Given the following invoice model:
validates :po_number, :invoice_number, :invoice_date, :date_received, :state_id, :division_id, :pending_state_id, :approver_username, :approver_email, :presence => true
validates :po_number, :uniqueness => {:scope => :invoice_number}
There are times when an invoice record is canceled (state_id = 4), but then needs to be re-created.
Can you help me with how to still validate uniqueness on po_number and invoice_number so the new record can be created even though the same combination exists with a different state_id if it was canceled?
Based on what you described, I believe it may be sufficient to include the :state_id in the scope and pass an :unless (or :if) option to exclude cancelled (or any other states) from the check:
validates :po_number, :uniqueness => {
:scope => [:invoice_number, :state_id],
:unless => :cancelled?
}
# assumes an instance method like
def cancelled?
state_id == 4
end
I think you'll need a custom validator. Something like this might work:
validate :unique_po_number
def unique_po_number
errors.add(:po_number, 'must be unique') if self.class.where('state != 4').where(:po_number => po_number).count > 0
end

Rails 3 validates_uniquess_of virtual field with scope

I am working on a Rails 3 app that is needing to run a validation on a virtual field to see if the record already exists... here is my model code:
#mass-assignment
attr_accessible :first_name, :last_name, :dob, :gender
#validations
validates_presence_of :first_name, :last_name, :gender, :dob
validates :fullname, :uniqueness => { :scope => [:dob] }
def fullname
"#{first_name} #{last_name}"
end
I am not getting any errors, its passing the validation.
I don't think you can do something like that with standard validates. Reason is, it usually is a "simple" sql look-up for uniqueness. But to check uniqueness of what's sent back from your method, it'd have to :
Get all entries of your scope
For each, execute the fullname method.
Add every result in an array while testing for uniqueness
Simple when the data set is small, but then it'd just take ages to do as soon as you reach 10K plus matches in your scope.
I'd personally do this with a standard before_save using the dob scope
before_save :check_full_name_uniqueness
def check_full_name_uniqueness
query_id = id || 0
return !Patient.where("first_name = ? and last_name = ? and dob = ? and id != ?", first_name, last_name, dob, query_id).exists?
end
Add error message (before the return):
errors.add(:fullname, 'Your error')
Back in the controller, get the error :
your_object.errors.each do |k, v| #k is the key of the hash, here fullname, and v the error message
#Do whatever you have to do
end

Rails 3/3.1 and I18n: Validation hits when switching between languages

The database is seeded with values in english language and format, e.g., :hourlyrate => 20.90. On first start (language is english by default), the input form displays the content of the field correctly. I can modify and save, no problem.
If I switch to german, the number is displayed correctly as 20,90. If I edit anything on this form, I can not save again, as the validation catches the number as not being valid.
My question is, do I have to perform corrections in my controller before saving, or did I miss some built-in function of Rails?
Relevant parts of the code
Helper:
def my_number_with_precision(value)
if value
# value
number_with_precision(value, :precision => 2)
end
end
Validation:
validates :hourlyrate, :numericality => { :greater_or_equal_than => 0, :message => " is an invalid number or below zero" }
Form:
<div class="input">
<%= f.text_field :hourlyrate, :value => my_number_with_precision(f.object.hourlyrate) %>
</div>
Gemfile
gem 'rails-i18n'
I came up with one of the following solutions - language specific code:
def parse_i18n(value)
if I18n.locale = 'de'
value.gsub(',', '.')
else
value
end
end
def parse_i18n(value)
value.gsub(I18n.t("number.currency.format.unit"),'').
gsub(I18n.t("number.currency.format.delimiter"), '').
gsub(I18n.t("number.currency.format.separator"), '.')
end

How to use MongoID validates_inclusion_of

I have a model with a field that can contain a list of values. I want that list to be limited to a subset. I want to use validates_inclusion_of, but probably misunderstand that validation.
class Profile
include Mongoid::Document
field :foo, :type => Array
validates_inclusion_of :foo, in: %w[foo bar]
end
p = Profile.new
p.valid? #=> false; this is correct, as it should fail on empty lists.
p.foo = ["bar"]
p.valid? #=> false; this is incorrect. I would expect it to pass now.
p.errors #=> {:foo=>["is not included in the list"]}
What am I doing wrong? Can validates_inclusion_of be used for arrays?
Your field value is an array (field :foo, :type => Array)
Validation expects field to be not an array to check its inclusion.
By your example validation is checking for ['foo', 'bar'].include?(['bar']) # => false
So correct your :in option in validates_inclusion_of:
validates_inclusion_of :foo, in: [['foo'], ['bar']]

How can I map between strings and attributes automatically?

I have a tiny logical error in my code somewhere and I can't figure out exactly what the problem is. Let's start from the beginning. I have the following extension that my order class uses.
class ActiveRecord::Base
def self.has_statuses(*status_names)
validates :status,
:presence => true,
:inclusion => { :in => status_names}
status_names.each do |status_name|
scope "all_#{status_name}", where(status: status_name)
end
status_names.each do |status_name|
define_method "#{status_name}?" do
status == status_name
end
end
end
end
This works great for the queries and initial setting of "statuses".
require "#{Rails.root}/lib/active_record_extensions"
class Order < ActiveRecord::Base
has_statuses :created, :in_progress, :approved, :rejected, :shipped
after_initialize :init
attr_accessible :store_id, :user_id, :order_reference, :sales_person
private
def init
if new_record?
self.status = :created
end
end
end
Now I set a status initially and that works great. No problems at all and I can save my new order as expected. Updating the order on the other hand is not working. I get a message saying:
"Status is not included in the list"
When I check it seems that order.status == 'created' and it's trying to match against :created. I tried setting the has_statuses 'created', 'in_progress' etc but couldn't get some of the other things to work.
Anyway to automatically map between string/attribute?
from your description, looks like you're comparing a string to a symbol. Probably need to add:
define_method "#{status_name}=" do
self.status = status_name.to_sym
end
or do a #to_s on the status_names