ChiefRockaChris
ChiefRockaChris

Reputation: 653

Rails Testing Default Value in database fails

Ok, so I am running a Postgres database in Rails 4 and for one of my models Offer the attribute :offer_status should default to declined. Here is my migration:

def change
    create_table :offers do |t|
      t.integer :offer_status, default: 0

      t.timestamps null: false
    end

This :offer_status attribute refers to an enum in the model like so:

class Offer < ActiveRecord::Base
 enum offer_status: [:declined, :accepted]
end 

With these two in place I have written a test that will check if a newly created offer will have a default offer_status of 0.

 test "new offers should default to declined" do
    @offer2=Offer.new()
    assert @offer2.declined?
  end

When I call the byebug console mid-test and puts @offer2 I get this:

(byebug) o
<Offer id: nil,  offer_status: nil, created_at: nil, updated_at: nil>
(byebug) exit 

However, if I do the exact same call o=Offer.new() in the rails console it returns:

 2.2.0 :001 > o=Offer.new
 => #<Offer id: nil, offer_status: 0, created_at: nil, updated_at: nil> 

So my question is, why does it work in the console but fail in my tests?

Upvotes: 1

Views: 1036

Answers (2)

codenighter
codenighter

Reputation: 348

I just had a similar problem. I had to change an already executed migration (to add a default to 0 and to specify null: false). I executed rake db:rollback STEP=1 and then I've rerun the migration. Everything worked fine, in rails console I was able to see that for every object created the default value for that attribute was 0, but in tests it was always nil. What it solved it for me was to drop the database (no important data there), recreate it, run the migrations and the tests were executed without failures or errors.

I should mention maybe, that even before I've dropped the database, in the schema.db for that column the default was already 0 and null: false. Maybe rake test uses a different schema, something cached, and not the newest one...

Upvotes: 0

Axel Tetzlaff
Axel Tetzlaff

Reputation: 1364

I'm not sure why it does behave differently in the tests, but what you should be aware of, is that the default: 0 is a instruction for your database. It becomes part of the table definition.

Calling new will create a new ruby object instance, which will have not touched the database until you try to save it. Defining a default just tells the database 'if you don't receive a value for this column, put 0 in it` - But until you send your new Object with save via a SQL query to the DB, this will have absolutely no effect on your object.

Upvotes: 3

Related Questions