Reputation: 1159
I have an update
-type method that I am trying to test in Rails using MiniTest and FactoryGirl. My problem is that although I can see that the update is happening correctly within the update function, it doesn't seem to carry over back into the test-function properly.
These is the objects we are working with, (obj
is given a default location
to start off with:
location1 = create :location
location2 = create :location
obj = create :object, location: location1
And then we call the update
function, which takes id
's:
obj.update_location(obj.id, location2.id)
The update
function:
def update_location(obj_id, loc_id)
@obj = Object.find(obj_id)
@obj.location_id = loc_id
@obj.save
end
But when, back in the test file, I try to assert
the change…
assert_equal obj.location_id, location2.id
...I get a failure. The console tells me that obj.location_id
still equals location1.id
! Why is this?
It seems that the @obj.save
is working properly because I inserted puts @obj.inspect
in the update-function and it outputs the correctly updated location_id
.
I don't think it has to do with transaction-rollbacks because this is all taking place within a single test. (And I am under the impression that transaction rollbacks only happen in between tests).
In summary, my question is: Why doesn't my update persist back into the rails MiniTest test
function?
EDIT: Here is the whole test:
test "update_location" do
location1 = create :location
location2 = create :location
#give the obj a starting `type`
obj = create :obj, location: location1
obj.update_location(obj.id, location2.id)
assert_equal obj.location_id, location2.id
end
Upvotes: 3
Views: 3039
Reputation: 1159
Issue is resolved, and here is my understanding:
The issue was in how rails' ORM work. The original object 'obj' is loaded up with data from the DB when it is created…but later changes to the DB are not automatically stored to obj
. I had thought that obj.some_attribute
looks at the database for the record obj
in order to find the attribute value--but in actuality I think that the attributes are simply loaded into the variable upon its creation and the database is NOT accessed if I call obj.some_attribute
at a later point in time.
Normally, when an update is done through the variable itself, Rails knows to update the variable for you. So when you write obj.some_attribute = 5
, and then later on write obj.some_attribute
, Rails knows the value is supposed to be 5. But that Rails magic doesn't happen in this situation because it's not updating the record through the variable.
So what needs to be done is simply to reload
the object from the database.
So assert_equal obj.reload.location_id, location2.id
works!
Upvotes: 6
Reputation: 8586
2 questions that might help you find an answer:
Why are you using an instance variable @obj
instead of a local variable obj
Why do you have a special method just to update 1 column. Would the update_column not work for you?
Upvotes: 0