2

I am running rails 3.1.3 with postgresql 9.1 and testing with Rspec. This is really a test app based on the railstutorial, as part of my quest to learn rails.

My problem is with the spec/models/employee_spec.rb tests. So far there are 34 examples and all pass except three and they are failing because of a not null constraint. Following are the failing tests:

it "should create a new instance given valid attributes" do
    Employee.create!(@attr)   
  end (------ the Employee.create!(@attr) seems to be the problem)

it "should reject duplicate email addresses" do
    # Put an employee with a given email address into the database.
    Employee.create!(@attr) 

    employee_with_duplicate_email = Employee.new(@attr)

    employee_with_duplicate_email.should_not be_valid
  end

it "should reject email addresses identical up to case" do
    upcased_email = @attr[:email].upcase

    Employee.create!(@attr.merge(:email => upcased_email))

    employee_with_upcase_email = Employee.new(@attr)

    employee_with_upcase_email.should_not be_valid
  end

Hopefully one of you who read this, if it is not too long, can give me some pointers as to how I get around this issue.(I could go into postgresql and change the attribute such that it accepts null values, but I would like to think that rspec should be able to deal with not null constraints)

Well, thank-you one and all for any help, pointers and guidance you can give.

Tom.

The table's schema:

# == Schema Information
#
# Table name: employees
#
#  id                        :integer         not null, primary key
#  first_name                :string(255)     not null
#  last_name                 :string(255)     not null
#  mi                        :text
#  marital_status            :string(255)     not null
#  gender                    :string(255)     not null
#  birth_date                :date            default(Sat, 20 Aug 1949), not null
#  hire_date                 :date            not null
#  term_date                 :date
#  primary_position          :string(255)     not null
#  trained_position          :string(255)
#  email                     :string(255)     not null
#  active                    :boolean         default(TRUE), not null
#  address1                  :string(255)     not null
#  address2                  :string(255)
#  city                      :string(255)     not null
#  zip_code                  :string(255)     not null
#  state                     :string(255)     not null
#  emp_home_ph               :string(255)
#  emp_mobile_ph             :string(255)
#  emer_contact_first_name   :string(255)
#  emer_contact_last_name    :string(255)
#  emer_contact_relationship :string(255)
#  emer_contact_ph           :string(255)
#  created_at                :datetime
#  updated_at                :datetime
#

The spec file (~/spec/models/employee_spec.rb):

require 'spec_helper'

describe Employee do

  before(:each) do
     @attr = { :first_name => "Teress", :last_name => "Pottle", :mi => "null",  
    :marital_status => "Single", :gender => "Female", :birth_date => '1987-04-20',  
    :hire_date => '2002-01-01', :term_date => "null", :active => "true",  
    :primary_position => "Job Coach", :trained_position => "null", :email =>   
    "[email protected]", :address1 => "1 First Ave", :address2 => "null", :city =>  
    "Frave", :zip_code => "54806", :state => "WI", :emp_home_ph => "null",  
    :emp_mobile_ph => "null", :emer_contact_first_name => "null",  
    :emer_contact_last_name => "null", :emer_contact_relationship => "null",  
    :emer_contact_ph => "null" }
   end

 it "should create a new instance given valid attributes" do
     Employee.create!(@attr)
 end

 it "should require a first_name" do
    no_first_name = Employee.new(@attr.merge(:first_name => ""))
    no_first_name.should_not be_valid
 end

 it "should reject first_name that is too long" do
   long_name = "a" * 26
   long_first_name = Employee.new(@attr.merge(:first_name => long_name))
   long_first_name.should_not be_valid
 end

 it "should require a last_name" do
   no_last_name = Employee.new(@attr.merge(:last_name => ""))
   no_last_name.should_not be_valid
 end

 it "should reject a last_name that is too long" do
   long_name = "a" * 26
   long_last_name = Employee.new(@attr.merge(:last_name => long_name))
   long_last_name.should_not be_valid
 end

 it "should require a marital_status" do
   no_marital_status = Employee.new(@attr.merge(:marital_status => ""))
   no_marital_status.should_not be_valid
 end

 it "should require a gender" do
   no_gender = Employee.new(@attr.merge(:gender => ""))
   no_gender.should_not be_valid
 end

 it "should require a birth_date" do
   no_birth_date = Employee.new(@attr.merge(:birth_date => ""))
   no_birth_date.should_not be_valid
 end

 it "should require a hire_date" do
   no_hire_date = Employee.new(@attr.merge(:hire_date => ""))
   no_hire_date.should_not be_valid
 end

 it "should require a primary_position" do
    no_primary_position = Employee.new(@attr.merge(:primary_position => ""))
    no_primary_position.should_not be_valid
 end

 it "should require a email" do
    no_email = Employee.new(@attr.merge(:email => ""))
    no_email.should_not be_valid
 end

 it "should require an 'active' setting" do
    no_active_setting = Employee.new(@attr.merge(:active => ""))
    no_active_setting.should_not be_valid
 end

it "should require an address1" do
    no_address1 = Employee.new(@attr.merge(:address1 => ""))
    no_address1.should_not be_valid
end

it "should require a city" do
   no_city = Employee.new(@attr.merge(:city => ""))
   no_city.should_not be_valid
end

it "should require a zip_code" do
   no_zip_code = Employee.new(@attr.merge(:zip_code => ""))
   no_zip_code.should_not be_valid
end

it "should require a state" do
   no_state = Employee.new(@attr.merge(:state => ""))
   no_state.should_not be_valid
end

it "should accept valid email addresses" do
   addresses = %w[[email protected] [email protected] [email protected]]
     addresses.each do |address|
       valid_email_employee = Employee.new(@attr.merge(:email => address))
       valid_email_employee.should be_valid
    end
end

it "should reject invalid email addresses" do
   addresses = %w[user@foo,com user_at_foo.org example.user@foo.]
      addresses.each do |address|
         invalid_email_employee = Employee.new(@attr.merge(:email => address))
         invalid_email_employee.should_not be_valid
      end
end

it "should reject duplicate email addresses" do
   # Put an employee with a given email address into the database.
   Employee.create!(@attr)
   employee_with_duplicate_email = Employee.new(@attr)
   employee_with_duplicate_email.should_not be_valid
end

it "should reject email addresses identical up to case" do
  upcased_email = @attr[:email].upcase
  Employee.create!(@attr.merge(:email => upcased_email))
  employee_with_upcase_email = Employee.new(@attr)
  employee_with_upcase_email.should_not be_valid
end
end

The Employee class (~/app/models/employee.rb):

 class Employee < ActiveRecord::Base

  attr_accessor :first_name, :last_name, :mi, :marital_status, :gender, :birth_date,  
 :hire_date, :term_date, :primary_position, :trained_position, :email, :active,  
 :address1, :address2, :city, :zip_code, :state, :emp_home_ph, :emp_mobile_ph,  
 :emer_contact_first_name, :emer_contact_last_name, :emer_contact_relationship, 
 :emer_contact_ph

 email_regex = /([\w+.]+)@[a-z0-9\-.]+\.[a-z]+/i
 date_regex = /^[0-9]{4}[-][0-9]{2}[-][0-9]{2}$/

 validates(:marital_status, :gender, :primary_position, :active, :address1, :city, 
 :zip_code, :state, :presence => true)
 validates(:first_name, :last_name, :presence => true, 
        :length => { :maximum => 25 })
 validates(:birth_date, :hire_date, :presence => true,
        :format => { :with => date_regex })
 validates(:email, :presence => true,
        :format => { :with => email_regex },
        :uniqueness => { :case_sensitive => false})
end

What happens when I run rspec:

loading autotest/rails_rspec2
/home/tom/.rvm/rubies/ruby-1.9.3-p0/bin/ruby -rrubygems -S /home/tom/.rvm/gems  
/ruby-1.9.3-p0@latest/gems/rspec-core-2.7.1/exe/rspec --tty  
'/home/tom/rails_projects/tracking /spec/controllers/employees_controller_spec.rb'   
'/home/tom/rails_projects/tracking/spec/controllers/pages_controller_spec.rb' '/home  
/tom/rails_projects/tracking/spec/models/employee_spec.rb' '/home/tom/rails_projects  
/tracking/spec/requests/layout_links_spec.rb'
........F.................FF......

Failures:

1) Employee should create a new instance given valid attributes
 Failure/Error: Employee.create!(@attr)
 ActiveRecord::StatementInvalid:
   PGError: ERROR:  null value in column "first_name" violates not-null constraint
   : INSERT INTO "employees" ("active", "address1", "address2", "birth_date", 
   "city", "created_at", "email", "emer_contact_first_name", 
   "emer_contact_last_name",  "emer_contact_ph", "emer_contact_relationship",
   "emp_home_ph", "emp_mobile_ph", "first_name", "gender", "hire_date", "last_name",
   "marital_status", "mi", "primary_position", "state", "term_date", 
   "trained_position", "updated_at", "zip_code")
    VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, 
    $17, $18, $19, $20, $21, $22, $23, $24, $25) RETURNING "id"
    # ./spec/models/employee_spec.rb:42:in `block (2 levels) in <top (required)>'

2) Employee should reject duplicate email addresses
 Failure/Error: Employee.create!(@attr)
 ActiveRecord::StatementInvalid:
   PGError: ERROR:  null value in column "first_name" violates not-null constraint
   : INSERT INTO "employees" ("active", "address1", "address2", "birth_date", "city",
   "created_at", "email", "emer_contact_first_name", "emer_contact_last_name",
  "emer_contact_ph", "emer_contact_relationship", "emp_home_ph", "emp_mobile_ph",
  "first_name", "gender", "hire_date", "last_name", "marital_status", "mi",
  "primary_position", "state", "term_date", "trained_position", "updated_at", 
  "zip_code") 
   VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, 
   $17, $18, $19, $20, $21, $22, $23, $24, $25) RETURNING "id"
   # ./spec/models/employee_spec.rb:140:in `block (2 levels) in <top (required)>'

3) Employee should reject email addresses identical up to case
 Failure/Error: Employee.create!(@attr.merge(:email => upcased_email))
 ActiveRecord::StatementInvalid:
   PGError: ERROR:  null value in column "first_name" violates not-null constraint
   : INSERT INTO "employees" ("active", "address1", "address2", "birth_date", "city",  
   "created_at", "email", "emer_contact_first_name", "emer_contact_last_name",
   "emer_contact_ph", "emer_contact_relationship", "emp_home_ph", "emp_mobile_ph",
   "first_name", "gender", "hire_date", "last_name", "marital_status", "mi",
   "primary_position", "state", "term_date", "trained_position", "updated_at",
   "zip_code") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14,  
   $15, $16,$17, $18, $19, $20, $21, $22, $23, $24, $25) RETURNING "id"
   # ./spec/models/employee_spec.rb:147:in `block (2 levels) in <top (required)>'

 Finished in 19.24 seconds
 34 examples, 3 failures

 Failed examples:

rspec ./spec/models/employee_spec.rb:41 # Employee should create a new instance given
valid attributes
rspec ./spec/models/employee_spec.rb:138 # Employee should reject duplicate email
addresses
rspec ./spec/models/employee_spec.rb:145 # Employee should reject email addresses
identical up to case
9
  • what is the error message you are getting? which "not null" constraint is being hit? Commented Dec 10, 2011 at 0:25
  • In addition show your table structure including constraint definitions. Commented Dec 10, 2011 at 1:32
  • Your test attributes (@attr) are incomplete, the error message will tell you which attribute is missing. Commented Dec 10, 2011 at 1:47
  • Hi, the first_name constraint is being hit, here is all that I can fit in this comment of the table structure, # id :integer not null, primary key # first_name :string(255) not null # last_name :string(255) not null # mi :text # marital_status :string(255) not null # gender :string(255) not null I do have @attr defined in the before(:each) do just after describe Employee do and all of the attributes are given values there. Commented Dec 10, 2011 at 3:07
  • You can edit your question to include more details. What does @attr look like? Commented Dec 10, 2011 at 3:36

1 Answer 1

2

Your problem isn't with your tests, your problem is with your Employee class. Your class starts with this:

class Employee < ActiveRecord::Base

  attr_accessor :first_name, :last_name, :mi, :marital_status, :gender, :birth_date,  
   :hire_date, :term_date, :primary_position, :trained_position, :email, :active,  
   :address1, :address2, :city, :zip_code, :state, :emp_home_ph, :emp_mobile_ph,  
   :emer_contact_first_name, :emer_contact_last_name, :emer_contact_relationship, 
   :emer_contact_ph

but you don't need or want to use attr_accessor here. Normal object attributes (which attr_accessor creates) are not the same as ActiveRecord attributes. ActiveRecord will examine the table's structure and create its own internal storage for the database-backed attributes and a suite of accessor and mutator methods for those attributes; internally, ActiveRecord will use those accessor methods to see what's in the object. Then, you use attr_accessor to declare the columns as object attributes and attr_accessor creates its own accessor and mutator methods which replace ActiveRecord's. The result is that object.first_name will be looking for the @first_name instance variable in object but there will be no such thing, Employee.create will set the first_name in ActiveRecord's attributes, not the @first_name instance value.

The solution is to get rid of the attr_accessor statement in your class. Then read the Rails Guides in parallel with your tutorial.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @mu is too short .... that was a winner .... I am off to read up on (attr_accessor). Thanks for your help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.