Rails 3: How do I validate to allow blanks ("") but not nil (NULL in database) - ruby-on-rails-3

In an ActiveRecord (or ActiveModel) I would like the following spec to pass
it { should allow_value("").for(:my_string) }
it { should_not allow_value(nil).for(:my_string) }
I have tried
validates :my_string, {
:length => { :in => 0..255 },
:presence => true,
:allow_blank => true,
:allow_nil => false,
}
and also
validates :my_string, {
:length => { :in => 0..255 },
:allow_blank => true,
:allow_nil => false,
}
But either it allows both "" and nil or none of them.

This works for me
validates :my_string, length: { in: 0..255, allow_nil: false }
If you just want to validate that the field is not null, but don't care about blank/empty strings, this works:
validates :my_string, length: { minimum: 0, allow_nil: false, message: "can't be nil" }

You can try doing:
validates :my_string, exclusion: { in: [nil]}
It is part of the validations themselves in ActiveRecord.
I've tried the others and all of them are very compliated or allow nil too.

You might need to do a custom validation for this:
validates :my_string, :length => { :in => 0..255 }
validate :my_string_is_valid
def my_string_is_valid
self.errors.add :base, 'My string can not be nil' if self.my_string.nil?
end

You can create a simple custom validator (placed in app/validators dir)
class NotNilValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors[attribute] << "must not be nil" if value.nil?
end
end
and then
validates :my_string, not_nil: true

Or maybe:
validates :my_string, :length => { :in => 0..255 }, :allow_nil => false
Seems that allow_nil does not override allow_blank.
So you better no specify allow_blank

This works for me:
validates_exclusion_of :my_string, in: [nil]

Related

Thinking Sphinx Scope Returning mix of Results and "blanks"

Controller:
#sites = Site.inspections_enabled_controllers_search.search("test")
#sites.each do |s|
if s == nil
puts "WHAT THE ...?"
end
ap s #print out the site
end
Model:
has_many :inspections_enabled_controllers,
:class_name => 'Controller',
:conditions => ['controllers.inspections_enabled = ?', true]
sphinx_scope(:inspections_enabled_controllers_search) {
{
:joins => :inspections_enabled_controllers
}
}
Returns:
#<Site:0x000000114618b8> {
:id => 156,
:name => "Test Site"
}
WHAT THE ...?
nil
WHAT THE ...?
nil
WHAT THE ...?
nil
#<Site:0x000000111c41a0> {
:id => 213,
:name => "TestRail V1.5 - SmartLine"
}
WHAT THE ...?
nil
WHAT THE ...?
nil
WHAT THE ...?
nil
WHAT THE ...?
nil
#<Site:0x00000011461200> {
:id => 220,
:name => "Activation Testing"
}
NOTICE the total of SEVEN "-" which are simply empty items in an array.
This worked for me
#sites = Site.inspections_enabled_controllers_search.search("test", :retry_stale => 1)
Reference:
http://pat.github.com/ts/en/searching.html#nils

Access all nodes in neo4j

On rails console i am trying to call
#invoice = Invoice.all
which returns me some object like
<Neo4j::Traversal::Traverser:0x817382>
but when i tried to loop over the object like
#invoice.each { |t| p t.number }
i got nil,but database contains data for invoice.
Invoice class
class Invoice < Searchable
include Neo4jrb::Paperclip
include LinkableEntity
include HeadsupNotify
enable_optimistic_locking
before_destroy :verify_links, :prepend => true
before_destroy :destroy_invoice_items
property :number, :type => :string
property :currency, :default => Money.default_currency.to_s
property :date, :pay_by_date, :type => :date
property :purchase_order_number
property :settle, :default => false
property :link_1, :link_2, :type => :string
index :number, :type => :fulltext
domain_property :details
money_property :total_cost, :receivable_amount
attr_protected :total_cost, :receivable_amount
attr_accessor :delink_receipt
validates :total_cost, :numericality => {:greater_than_or_equal_to => 0}
validates :receivable_amount, :numericality => {:greater_than_or_equal_to => 0}
validates :date,:number, :customer_id, :event_id, :project_id, :department_id,
:brand_id, :premise_id, :user_id, :currency, :presence => true
validates :link_1, :length => { :maximum => 250 }
validates :link_2, :length => { :maximum => 250 }
validate :number_uniqueness
validate :invoice_items_present
validate :invoice_items_currency
validate :issue_credit_notes_valid
validate :pay_by_date_valid, :unless => "date.nil?"
validate :check_not_linked, :on => :update
has_one(:event).from(Event, :invoices_for_event)
has_one(:project).from(Project, :invoices_for_project)
has_one(:department).from(Department, :invoices_for_department)
has_one(:brand).from(Brand, :invoices_for_brand)
has_one(:premise).from(Premise, :invoices_for_premise)
has_one(:user).to(User)
has_one(:customer).from(Customer, :invoices_for_customer)
alias :party :customer
has_n(:invoice_items).to(InvoiceItem)
has_n(:receipts).from(Receipt, :paid_invoices)
has_n(:issue_credit_notes).from(IssueCreditNote, :credit_notes_for_invoice)
has_one(:invoices_for_settle).to(Settle)
links :receipts, :issue_credit_notes,:invoices_for_settle
has_neo4jrb_attached_file :photo
{:customer => :name, :event => :name, :department => :name, :project => :name, :brand => :name,
:premise => :name, :user => :email}.each do |target, method|
delegate method, :to => target, :prefix => true, :allow_nil => true
end
accepts_id_for :customer, :event, :project, :department, :brand, :premise, :user
accepts_nested_attributes_for :invoice_items, :allow_destroy => true
validates_associated :invoice_items
validates :customer_name, :presence => true, :length => { :maximum => 100 }
validates :event_name, :presence => true, :length => { :maximum => 100 }
validates :premise_name, :presence => true, :length => { :maximum => 100 }
validates :project_name, :presence => true, :length => { :maximum => 100 }
validates :brand_name, :presence => true, :length => { :maximum => 100 }
validates :department_name, :presence => true, :length => { :maximum => 100 }
validates :link_1, :length => { :maximum => 250 }
validates :link_2, :length => { :maximum => 250 }
after_validation :set_total_cost
serialize :methods => :invoice_items
before_validation :delink
Can anyone please help me with this?
Thanks in advance.
I'm not exactly sure of how to do this with Ruby On Rails, but if your Invoice objects (nodes) are in a lucene full text index, you could use a Cypher query to return all Invoices.
Something like:
START invoices=node:Invoices('name: *') RETURN invoices;

rails-rspec uniqueness validation using accepts_nested_attributes_for

My models relationship like
class Cart < ActiveRecord::Base
has_many :cart_items, :inverse_of => :cart, :dependent => :destroy
accepts_nested_attributes_for :cart_items, :allow_destroy => :true, :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
validates_associated :cart_items
validates :cart_name, :presence => {:message => "Must be filled" }
end
class CartItem < ActiveRecord::Base
belongs_to :cart, :inverse_of => :cart_items
validates :cart_item_no, :presence => {:message => "Must be filled"}, :uniqueness => {:message => "Already exists" }
end
factories.rb
FactoryGirl.define do
factory :cart do
cart_name "sample"
factory :cart_with_cart_items do
after(:build) {|cart|
2.times { cart.cart_items.build(attributes_for(:cart_item)) }
}
after(:create) {|cart|
cart.cart_items.each {|cart_item| cart_item.save! }
}
end
end
factory :cart_item do
cart_item_no 1
cart
end
end
Below test case always fails
it "should not be valid with same cart_id" do
cart = FactoryGirl.build(:cart_with_cart_items)
cart.should_not be_valid
end
then I exploring in console, validation always returning true with same *cart_item_no* twice in cart_items by the example of below code.
cart = Cart.new(:cart_name => "yyy")
=> #<Cart id: nil, cart_name: "yyy">
2.times { cart.cart_items.build(:cart_item_no => 1000) }
=> 2
cart.cart_items
=> [#<CartItem id: nil, cart_item_no: 1000>, #<CartItem id: nil, cart_item_no: 1000>]
cart.valid?
=> true
cart.save!
=> true
Is this rails problem?
how to solve test case?
Uniqness validation checks against the database only. In your case, you have two cart_items that conflict with each other but not with any record in the database, so individually, both are valid, which is why your validations passes.
You could add a custom validation in your Cart class (not tested):
validates :unique_cart_items
def unique_cart_items
unless cart_items.collect(&:cart_item_no).uniq.size < cart_items.size
# set some error attribute here
end
end
This compares the number of unique cart_item_no values to the number of cart_items. If they are not the same, there's a duplicate cart_item_no.

rails 3 Validate presence based off boolean

I have a model that has a boolean called draft
I want to validate presence of fields only if draft == false.
my model
if self.draft == false
validates :name, :presence => true, :length => { :maximum => 45 }
validates :description, :presence => true
validates :blurb, :presence => true, :length => { :maximum => 175 }
validates :category_id, :presence => true
validates :location_id, :presence => true
validates :goal, :presence => true
else
end
in my controller
def new
#item.new(:draft => false) || #item.new(:draft => true)
def create
if params[:commit] == "Create Item"
#cause = Item.new(params[:item], :draft => false)
elsif params[:commit] == "Save Changes"
#cause = Item.new(params[:item], :draft => true)
end
It completely ignores my if statement and validates anyways whether it's true or not upon clicking Save Changes.
Suggestions would be greatly appreciated.
A conditional validation looks like below
validates :name, :presence => true, :length => { :maximum => 45 }, :if => :draft_is_false?
private
def draft_is_false?
draft == false
end
Similarly, you can perform conditional validations on other fields and these can be grouped as well. Go through the Conditional Validations sections on Ruby on Rails guides.
Here is a one liner in newer rails syntax:
validates :name, presence: true, length: { maximum: 45 }, if: -> (item) { item.draft? }
Notice that there is a question mark after the draft attribute. Rails automatically create methods like draft? for all attributes on a model, and is basically a shortcut for attr.present?. When used with Boolean attributes, it suggests that the developer's intention is to check for true/false.

validate email format only if not blank Rails 3

I want to validate the email only if the email has been entered.
I tried the following:
validates :email, :presence => {:message => "Your email is used to save your greeting."},
:email => true,
:if => Proc.new {|c| not c.email.blank?},
:uniqueness => { :case_sensitive => false }
However this does not work as it stops error messages from showing when the email is left blank.
How can I validate the presence of the email when it is missing and ONLY validate the format when it has been entered?
This should do the trick.
validates :email,:presence => {:message => "Your email is used to save your greeting."}, :allow_blank => true,:uniqueness => { :case_sensitive => false }
Use:allow_blank => true or :allow_nil => true, :if => :email?
edit: fix typo.
You can write custom validation function:
class Model < ActiveRecord::Base
validate :check_email
protected
def check_email
if email.blank?
validates :email, :presence => {:message => "Your email is used to save your greeting."}
else
validates :email,
:email => true,
:uniqueness => { :case_sensitive => false }
end
end
end
or divide your validator into 2 separate validators with conditions:
validates :email,
:presence => {:message => "Your email is used to save your greeting."},
:if => Proc.new {|c| c.email.blank?}
validates :email,
:email => true,
:uniqueness => { :case_sensitive => false }
:unless => Proc.new {|c| c.email.blank?}
you can validate format if no precense required
:allow_nil => true