views:

41

answers:

0

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