Today I faced a very weird error using polymorphic associations. In the rails console everything does almost often work, but the unit tests are failing all the time.
I setup a test Rails 3.1.3. (edit: upgraded to 3.2.3) app here (using SQLlite, but same error happens with mysql) https://github.com/easychris/Polymorphic_Test_Error
See also this issue: rails/rails#3882
To see the problem simply
cd polymorphic_test_error
bundle install
bundle exec rake db:setup
bundle exec rake db:fixtures:load
(but I guess you already know that ;-))
Basically, using the polymorphic association in the console like this works:
Company.find(1).users.size == 2 # returns true
But the test case which does the same fails. I've found out that it fails in the console as well if you use these two calls (basically this is what the test does, in the same order, thus it fails):
Company.find(1).designers.size == 1 # returns true
Company.find(1).users.size == 2 # now returns false, but should be true!
Same result if you run
bundle exec rake test:units
I've tried to simplify my existing database model as much as possible, so I can showcase the error with five models. Basically we have a Company, which has one or more departments. Each department has one or more users.
And now via polymorphic association each user can either have a Designer or Developer entity.
schema.rb:
ActiveRecord::Schema.define(:version => 20111207002230) do
create_table "companies", :force => true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "departments", :force => true do |t|
t.string "title"
t.integer "company_id"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "designers", :force => true do |t|
t.string "favorite_color"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "developers", :force => true do |t|
t.string "favorite_software"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", :force => true do |t|
t.string "name"
t.integer "typeable_id"
t.string "typeable_type"
t.integer "department_id"
t.datetime "created_at"
t.datetime "updated_at"
end
end
company.rb (model)
class Company < ActiveRecord::Base
has_many :departments
has_many :users, through: :departments
has_many :developers, source_type: 'Developer', source: :typeable , through: :users
has_many :designers, source_type: 'Designer', source: :typeable, through: :users
end
department.rb (model)
class Department < ActiveRecord::Base
has_many :users
belongs_to :company
end
user.rb (model)
class User < ActiveRecord::Base
belongs_to :typeable, :polymorphic => true
end
designer.rb (model)
class Designer < ActiveRecord::Base
has_one :user, :as => :typeable
end
developer.rb (model)
class Developer < ActiveRecord::Base
has_one :user, :as => :typeable
end