In a nutshell:
If you require your Rails models manually, pay attention to the path you use. Unless you have to, don't do it at all.
Background
Consider these classes:
# app/models/user.rb
class User < ActiveRecord::Base
validate :magic
def magic
errors.add_to_base('failed') if bad_things?
end
end
^
# app/models/foo.rb
require 'user'
class Foo
# something happens here
end
Now, when your environment is booted, Rails will automatically load your models, like User
.
In our example, when Foo
gets loaded, it will require
the User
class itself again. Since Ruby 1.8 identifies required files by the string you used (as you alread know), this will mean the User
class is required a second time.
This, in turn, will lead to the effect that User#magic
is called twice when a User
record is validated.
Note that loading classes a second time will lead to all kinds of trouble. Stay away from that, Kids!
Fixing it
You have two options:
-
Don't do it. Rails will load your models, so there is almost no reason to load it yourself.
-
If you absolutely have to do it, use the path that Rails would use. In my case, the only correct answer would have been:
require File.join(Rails.root, 'app/models/user')
It gets worse
The problem gets more strange when this issue "magically" appears or disappears.
If the Foo
class from our example is not being auto-loaded, all will be fine for the most time, but you will encounter validation errors being added twice occasionally.
This happened to me when during tests: a spec was referring to Foo
, which was not yet loaded, because it was in lib/foo.rb
. When the spec was run, Rails loaded the class the first time it was referred to, causing user
to be loaded, which Ruby believed it had not seen before. And that caused a completely different spec to fail at a later point of the spec run, because now User
ran its manual validation method twice.
Consider the fun you'll have when running tests in parallel.