I have a before :each
in my specs that looks like this:
before :each do
@user1 = create(:user, gender: 0)
@user2 = create(:user)
@membership1 = create(:membership, member: nil, family_tree: @user1.family_tree, inviter: @user1, invited: @user2, relation: "sister", relative_type: 1)
@membership2 = create(:membership, member: nil, family_tree: @user2.family_tree, inviter: @user2, invited: @user1, relation: "brother", relative_type: 1)
@connection = create(:connection, inviter_membership: @membership1, invited_membership: @membership2, inviter_user: @user1, invited_user: @user2, request_status: 1)
sign_in @user1
end
And this is my unit test in question:
it "should swap ownership of the inviter_membership - aka make invited_user the inviter_user on that inviter_membership" do
delete :destroy, id: @user1
expect(@membership1.inviter).to be @user2
end
All my controller does is destroys the record passed in via the ID, like so:
def destroy
@user = User.find(params[:id])
if @user.destroy
redirect_to root_path, notice: "You have successfully cancelled your account."
else
redirect_to :back
end
end
However, in my User
model, I have a before_destroy :callback
and my associations like so:
class User < ActiveRecord::Base
before_destroy :convert_user_to_members
has_many :memberships
has_many :inviter_memberships, class_name: "Membership", foreign_key: "user_id"
has_many :invited_memberships, class_name: "Membership", foreign_key: "invited_id"
has_many :inviter_connections, class_name: "Connection", foreign_key: "inviter_user_id"
has_many :invited_connections, class_name: "Connection", foreign_key: "invited_user_id"
private
def convert_user_to_members
inviter_mems = self.inviter_memberships
if !inviter_mems.empty?
inviter_mems.each do |membership|
if membership.user?
member = Member.create(first_name: self.first_name, last_name: self.last_name, email: self.email, bio: self.bio, gender: self.gender, avatar: self.avatar, birthday: self.birthday, deceased: false)
invited_user = membership.invited
membership.update!(member: member, inviter: invited_user, invited: nil, relative_type: 0)
if !membership.inviter_connection.nil?
connection = membership.inviter_connection
connection.update!(inviter_membership: membership, invited_membership: nil, inviter_user: invited_user, invited_user: nil, request_status: 3)
end
end
end
end
end
For the first binding.pry
which is at the top of my test (i.e. before the destroy is called and the callback executed) this is what I get at my console:
78: it "should swap ownership of the inviter_membership - aka make invited_user the inviter_user on that inviter_membership" do
=> 79: binding.pry
80: delete :destroy, id: @user1
81: binding.pry
82: expect(@membership1.inviter).to be @user2
83: end
84: #
[1] pry()> @user1.name
=> "Maybell McKenzie"
[2] pry()> @user2.name
=> "Joey Stanton"
[3] pry()> @membership1.inviter.name
=> "Maybell McKenzie"
[4] pry()> @membership1.invited.name
=> "Joey Stanton"
[5] pry()> @membership1.member
=> nil
For the second binding.pry
, that gets executed within my callback, this is what happens:
226: invited_user = membership.invited
227: membership.update!(member: member, inviter: invited_user, invited: nil, relative_type: 0)
=> 228: binding.pry
229: if !membership.inviter_connection.nil?
231: connection = membership.inviter_connection
232: connection.update!(inviter_membership: membership, invited_membership: nil, inviter_user: invited_user, invited_user: nil, request_status: 3)
233: end
[6] pry(#<User>)> self.name
=> "Maybell McKenzie"
[7] pry(#<User>)> invited_user.name
=> "Joey Stanton"
[8] pry(#<User>)> membership.inviter.name
=> "Joey Stanton"
[9] pry(#<User>)> membership.invited
=> nil
[10] pry(#<User>)> membership.member.name
=> "Maybell McKenzie"
Notice a few things:
- the record currently being evaluated is a
user
record, that has the same name as@user1
in the firstbinding.pry
- which is good. - the
invited_user
is correctly set to the same user record as@user2
above. - the
membership.inviter.name
is now the same asinvited_user.name
...aka...the swap has been successful. - the
membership.invited
attribute is now set tonil
. - there is now a
membership.member
attribute and it is correctly set to the same user as@user1
.
So, we are good so far. The next binding occurs AFTER the destroy has been completed. This is where things go awry. Remember there are no dependent: :destroy
on any of the membership
associations in my User
model.
But this is the outcome of the third binding.pry
:
78: it "should swap ownership of the inviter_membership - aka make invited_user the inviter_user on that inviter_membership" do
79: binding.pry
80: delete :destroy, id: @user1
=> 81: binding.pry
82: expect(@membership1.inviter).to be @user2
83: end
[2] pry()> @user1.name
=> "Maybell McKenzie"
[3] pry()> @user2.name
=> "Joey Stanton"
[4] pry()> @membership1.inviter.name
=> "Maybell McKenzie"
[5] pry()> @membership1.invited.name
=> "Joey Stanton"
[6] pry()> @membership1.member
=> nil
Notice that everything looks identical to the first binding.pry
.
If you dig deeper, you will notice that it seems that the record associated with @membership1
was actually destroyed....despite the fact that it shouldn't have been.
[7] pry()> Membership.count
=> 1 # this should be 2, because no membership record should be deleted.
[8] pry()> Membership.all
=> [#<Membership id: 1986, family_tree_id: 34158, user_id: 14266, created_at: "2016-01-31 05:29:37", updated_at: "2016-01-31 05:29:37", relation: "brother", member_id: nil, invited_id: 14265, relative_type: 1>]
[9] pry()> @user1.id
=> 14265
[10] pry()> @user2.id
=> 14266
So why does the result of my test, not sync up with the results returned by my callback? Or how do I see the exact results sent from my callback to the test? There anyway for me to inspect that?
Aucun commentaire:
Enregistrer un commentaire