1

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?

ChiefRockaChris
  • 643
  • 5
  • 21

2 Answers2

3

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.

Axel Tetzlaff
  • 1,355
  • 8
  • 11
  • I added a @offer2.save! in between the two lines of my test and it still saves as nil. Any idea why? – ChiefRockaChris Sep 21 '15 at 02:39
  • No sorry, add a validation `validates :offer_status, presence: true` to your model class and a NOT-NULL constraint `t.integer :offer_status, default: 0, null: false ` - this way NIL can not be stored in the db, and you will get pointed to the place where it actually fails – Axel Tetzlaff Sep 21 '15 at 09:46
  • Even with the validation and the db constraint everything still comes up as nil, I can't figure out why. – ChiefRockaChris Sep 24 '15 at 00:44
0

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...

codenighter
  • 348
  • 1
  • 4
  • 11