Why is ActiveRecord inserting NULL in the type column of an STI model?
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 (ie '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 type
column, 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:
mysql> ALTER TABLE users MODIFY COLUMN type varchar(50) NOT NULL DEFAULT 'User';
...[ok]
mysql> exit
Bye
$> bundle exec rake db:test:prepare # <-- My Mistake
...[ok]
I thought this was all I had to do, but it turns out running db:test:prepare
just matches your test database to your schema.rb
file, and my schema.rb
file hadn't been updated, so then User.create
worked in development, but broke in testing :D
Eventually, I came to understand all of the above, in addition to the fact that I needed to run db:migrate
in order to update my schema.rb
file BEFORE running db:test:prepare
. Once I did that: voila! User.create
actually used the default value of the type
column to insert new User objects.
Moral of the story:
db:schema:load
and start over with new dev data! (Or get a production dump or something) 使用不同于“type”的列名称
链接地址: http://www.djcxy.com/p/49734.html