Consider a simple User -> has_many -> Item, and of course Item ->
belongs_to -> User as the inverse.
Fabricator(:item) do
name 'thingy'
end
Fabricator(:user) do
name 'joe'
items(count: 1)
end
Now say we want to give that thingy to another user. I have a simple
model method called Item.give!(receiver) which will do it:
def give!(receiver)
self.user_id =
receiver.id
self.save(validate: false)
end
I had the validate: false in there because if validations change in
future and there is invalid data or something, I still want to be able
to "give!" items to other users.
Anyway, I wrote a simple test for this:
joe = Fabricate(:user)
tom = Fabricate(:user, name: 'tom')
item = joe.items.first
item.give!(tom)
# force reload from database
item = Item.find(
item.id)
tom = User.find(
tom.id)
joe = User.find(
joe.id)
assert item.user_id ==
tom.id
assert tom.items.size == 2
assert joe.items.size == 0
Alas, the test fails at the first assertion, even though the model
code works fine outside of Fabricator. However, if I remove the
validate: false in the model method, the test passes.
Also if I change the model to do "self.user = receiver.user" Instead
of setting the _id directly, it also works, i.e. I can leave the
validate: false in place.
Item has a validates_presence_of :user on Item if that makes any
difference. Pretty confusing that some trivial changes in the model
fix the test, and unfortunately the test fails on what is code that
actually works :(
Not sure if I've uncovered a bug, or just using rails nuances that
fabrication gem doesn't like, such as setting the _id of an
association without also setting the association along with it.
ActiveRecord deals with it fine outside of Fabricator, but inside
Fabricator it seems changing the ID of an association directly does
not trigger any update on the database.