save(validate: false)

63 views
Skip to first unread message

Danial Pearce

unread,
Aug 29, 2013, 9:20:32 AM8/29/13
to fabrica...@googlegroups.com
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.

Paul Elliott

unread,
Aug 29, 2013, 9:34:14 AM8/29/13
to fabrica...@googlegroups.com
The nuances you are uncovering have to do with ActiveRecord. Fabrication sets attributes on models the same way you would in a controller. These issues have to do with the way ActiveRecord sets the user vs the user_id, which are separate attrs in your model. What you are describing happens because if you set the user_id directly, then the user attr won't be present automatically. If you change your `give` method to set the receiver instead of the underlying ids then it should work. Alternatively, you could try changing the validation from user to user_id, which is what you are ultimately trying to verify anyway.

-- Paul

--
You received this message because you are subscribed to the Google Groups "fabrication" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fabricationge...@googlegroups.com.

Reply all
Reply to author
Forward
0 new messages