I want to validate that at least one of two columns have a value in my model. I found somewhere on the web that I could create a custom validator as follows:
# Check for the presence of one or another field:
# :validates_presence_of_at_least_one_field :last_name, :company_name - would require either last_name or company_name to be filled in
# also works with arrays
# :validates_presence_of_at_least_one_field :email, [:name, :address, :city, :state] - would require email or a mailing type address
module ActiveRecord
module Validations
module ClassMethods
def validates_presence_of_at_least_one_field(*attr_names)
msg = attr_names.collect {|a| a.is_a?(Array) ? " ( #{a.join(", ")} ) " : a.to_s}.join(", ") + "can't all be blank. At least one field must be filled in."
configuration = { :on => :save, :message => msg }
configuration.update(attr_names.extract_options!)
send(validation_method(configuration[:on]), configuration) do |record|
found = false
attr_names.each do |a|
a = [a] unless a.is_a?(Array)
found = true
a.each do |attr|
value = record.respond_to?(attr.to_s) ? record.send(attr.to_s) : record[attr.to_s]
found = !value.blank?
end
break if found
end
record.errors.add_to_base(configuration[:message]) unless found
end
end
end
end
end
I put this in a file called lib/acs_validator.rb in my project and added "require 'acs_validator'" to my environment.rb. This does exactly what I want. It works perfectly when I manually test it in the development environment but when I write a unit test it breaks my test environment.
This is my unit test:
require 'test_helper'
class CustomerTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end
test "customer not valid" do
puts "customer not valid"
customer = Customer.new
assert !customer.valid?
assert customer.errors.invalid?(:subdomain)
assert_equal "Company Name and Last Name can't both be blank.", customer.errors.on(:contact_lname)
end
end
This is my model:
class Customer < ActiveRecord::Base
validates_presence_of :subdomain
validates_presence_of_at_least_one_field :customer_company_name, :contact_lname, :message => "Company Name and Last Name can't both be blank."
has_one :service_plan
end
When I run the unit test, I get the following error:
DEPRECATION WARNING: Rake tasks in vendor/plugins/admin_data/tasks, vendor/plugins/admin_data/tasks, and vendor/plugins/admin_data/tasks are deprecated. Use lib/tasks instead. (called from /usr/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/tasks/rails.rb:10)
Couldn't drop acs_test : #<ActiveRecord::StatementInvalid: PGError: ERROR: database "acs_test" is being accessed by other users
DETAIL: There are 1 other session(s) using the database.
: DROP DATABASE IF EXISTS "acs_test">
acs_test already exists
NOTICE: CREATE TABLE will create implicit sequence "customers_id_seq" for serial column "customers.id"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "customers_pkey" for table "customers"
NOTICE: CREATE TABLE will create implicit sequence "service_plans_id_seq" for serial column "service_plans.id"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "service_plans_pkey" for table "service_plans"
/usr/bin/ruby1.8 -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" "test/unit/customer_test.rb" "test/unit/service_plan_test.rb" "test/unit/helpers/dashboard_helper_test.rb" "test/unit/helpers/customers_helper_test.rb" "test/unit/helpers/service_plans_helper_test.rb"
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.8/lib/active_record/base.rb:1994:in `method_missing_without_paginate': undefined method `validates_presence_of_at_least_one_field' for #<Class:0xb7076bd0> (NoMethodError)
from /usr/lib/ruby/gems/1.8/gems/will_paginate-2.3.12/lib/will_paginate/finder.rb:170:in `method_missing'
from /home/george/projects/advancedcomfortcs/app/models/customer.rb:3
from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
from /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
from /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:158:in `require'
from /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:265:in `require_or_load'
from /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:224:in `depend_on'
from /usr/lib/ruby/gems/1.8/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:136:in `require_dependency'
from /usr/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/initializer.rb:414:in `load_application_classes'
from /usr/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/initializer.rb:413:in `each'
from /usr/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/initializer.rb:413:in `load_application_classes'
from /usr/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/initializer.rb:411:in `each'
from /usr/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/initializer.rb:411:in `load_application_classes'
from /usr/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/initializer.rb:197:in `process'
from /usr/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/initializer.rb:113:in `send'
from /usr/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/initializer.rb:113:in `run'
from /home/george/projects/advancedcomfortcs/config/environment.rb:9
from ./test/test_helper.rb:2:in `require'
from ./test/test_helper.rb:2
from ./test/unit/customer_test.rb:1:in `require'
from ./test/unit/customer_test.rb:1
from /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5:in `load'
from /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5
from /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5:in `each'
from /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5
rake aborted!
Command failed with status (1): [/usr/bin/ruby1.8 -I"lib:test" "/usr/lib/ru...]
(See full trace by running task with --trace)
It seems to have stepped on will_paginate somehow.
Does anyone have any suggestions? Is there another way to do the validation I'm attempting to do?
Thanks,
George