I'm working on porting a very large Rails project from DataMapper to ActiveRecord. Among the models that has to be ported is a set of User models that used Single Table Inheritance (STI) to distinguish one type from another. Here is a simplified version of what it looks like:
class User < ActiveRecord::Base
...
end
class AdminUser < User
...
end
Generally, the 'type' field is used to tell the difference between Users and AdminUsers, by storing the class name of the object being saved (i.e. 'AdminUser'). And it works fine in development, but when I try User.create in the test environment, I get:
ActiveRecord::StatementInvalid: Mysql::Error: Column 'type' cannot be null
ActiveRecord tries to insert a new row, setting the type column to NULL... what could cause this to be happening in the test environment, but not in development?
Turns out it was a slight difference in the database table itself that was causing a change in behavior for ActiveRecord. The test database had no default value for the
typecolumn, whereas in development, the default value was'User'. Apparently ActiveRecord uses the default value when inserting data for an object of the primary class type (the class that inherits from ActiveRecord::Base - in this case,User). Why it doesn't just use the class name is beyond my understanding!My real confusion came when I updated my dev database to have a default for the type column, which I actually knew it needed, because somehow the production database already had one, so clearly my dev database was just out of sync. So I did this:
I thought this was all I had to do, but it turns out running
db:test:preparejust matches your test database to yourschema.rbfile, and myschema.rbfile hadn't been updated, so thenUser.createworked in development, but broke in testing :DEventually, I came to understand all of the above, in addition to the fact that I needed to run
db:migratein order to update myschema.rbfile BEFORE runningdb:test:prepare. Once I did that: voila!User.createactually used the default value of thetypecolumn to insert new User objects.Moral of the story:
db:schema:loadand start over with new dev data! (Or get a production dump or something)