Search code examples
ruby-on-railsruby-on-rails-4rspecfactory-botrspec-rails

Why are my factories and test not working like I expect?


I am using RSpec and Factory Girl.

Here are my associations at a high-level:

User 
  has_one :family_tree, dependent: :destroy
  has_many :memberships, through: :family_tree, dependent: :destroy

Family Tree
  belongs_to :user
  has_many :memberships, dependent: :destroy
  has_many :members, through: :memberships, dependent: :destroy

Membership
  belongs_to :family_tree
  belongs_to :user
  belongs_to :member

Member
  has_many :memberships, dependent: :destroy

This is the method my_relatives on my User class:

  def my_relatives
    self.family_tree.memberships.pluck(:relation)
  end

These are my factories:

User

  factory :user do
    association :family_tree
    first_name { Faker::Name.first_name }
    last_name { Faker::Name.last_name }
    email { Faker::Internet.email }
    password "password123"
    password_confirmation "password123"
    bio { Faker::Lorem.paragraph }
    invitation_relation { Faker::Lorem.word }
    # required if the Devise Confirmable module is used
    confirmed_at Time.now
    gender 1
  end

Member

  factory :member do
    first_name { Faker::Name.first_name }
    last_name { Faker::Name.last_name }
    email { Faker::Internet.email }
    bio { Faker::Lorem.paragraph }
    gender 1
  end

Memberships

  factory :membership do
    family_tree
    user
    relation { Faker::Lorem.word }
    member
  end

Family Tree

  factory :family_tree do
    name { Faker::Name.name }
  end

This my test:

  it "should return all the relatives of a user" do
    u1 = create(:user)
    ft = create(:family_tree, user: u1)
    relation = "nephew"
    u2 = create(:user)
    membership = create(:membership, user: u2, relation: relation, family_tree: ft)
    expect(u1.my_relatives).to eq(u2.memberships.where(relation: relation).pluck(:relation))
  end

When I run RSpec, this is the error I am getting:

  1) User should return all the relatives of a user
     Failure/Error: expect(u1.my_relatives).to eq(u2.memberships.where(relation: relation).pluck(:relation))

       expected: []
            got: ["nephew"]

       (compared using ==)

Why am I getting an empty array as my primary expectation for u1.my_relatives?

When I am going through the variables at runtime with pry, I get this:

1] pry(#<RSpec::ExampleGroups::User>)> u1
=> #<User id: nil, email: "[email protected]", encrypted_password: "$2a$04$EJWX5sLmBtDBgyA8tf35y.1FfhQcLRY3EAU/JxL8/tN...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: "2015-10-26 23:15:30", updated_at: "2015-10-26 23:15:30", first_name: "Brooks", confirmation_token: nil, confirmed_at: "2015-10-26 23:15:27", confirmation_sent_at: nil, unconfirmed_email: nil, invitation_relation: "similique", avatar: nil, invitation_token: nil, invitation_created_at: nil, invitation_sent_at: nil, invitation_accepted_at: nil, invitation_limit: nil, invited_by_id: nil, invited_by_type: nil, invitations_count: 0, bio: "Reiciendis ea omnis. Saepe ea amet nostrum deserun...", last_name: "Yost", gender: 1>
[2] pry(#<RSpec::ExampleGroups::User>)> ft
=> #<FamilyTree id: nil, name: "Ms. Milan Goldner", user_id: 1197, created_at: "2015-10-26 23:15:30", updated_at: "2015-10-26 23:15:30">
[3] pry(#<RSpec::ExampleGroups::User>)> relation
=> "nephew"
[4] pry(#<RSpec::ExampleGroups::User>)> u2
=> #<User id: nil, email: "[email protected]", encrypted_password: "$2a$04$z.UVWka/mRKCK6hp33LOuuBHaL8S7h1LnmWbonMfBkd...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: "2015-10-26 23:15:30", updated_at: "2015-10-26 23:15:30", first_name: "Adrien", confirmation_token: nil, confirmed_at: "2015-10-26 23:15:27", confirmation_sent_at: nil, unconfirmed_email: nil, invitation_relation: "repellat", avatar: nil, invitation_token: nil, invitation_created_at: nil, invitation_sent_at: nil, invitation_accepted_at: nil, invitation_limit: nil, invited_by_id: nil, invited_by_type: nil, invitations_count: 0, bio: "Rerum sunt ratione labore deserunt. Et quibusdam s...", last_name: "Renner", gender: 1>
[5] pry(#<RSpec::ExampleGroups::User>)> membership
=> #<Membership id: 126, family_tree_id: 1649, user_id: 1198, created_at: "2015-10-26 23:15:30", updated_at: "2015-10-26 23:15:30", relation: "nephew", member_id: 75, connection_sent_at: nil, connection_responded_at: nil, connect_send_limit: nil, connect_times_sent: nil, connected: nil, connect_type: nil, request_status: nil, connection_removed_at: nil>
[6] pry(#<RSpec::ExampleGroups::User>)> u1.my_relatives
=> []
[7] pry(#<RSpec::ExampleGroups::User>)> u1.family_tree
=> #<FamilyTree id: nil, name: "Ms. Milan Goldner", user_id: 1197, created_at: "2015-10-26 23:15:30", updated_at: "2015-10-26 23:15:30">
[8] pry(#<RSpec::ExampleGroups::User>)> u1.family_tree.memberships
=> []
[9] pry(#<RSpec::ExampleGroups::User>)> u1.memberships
=> []
[11] pry(#<RSpec::ExampleGroups::User>)> membership
=> #<Membership id: 126, family_tree_id: 1649, user_id: 1198, created_at: "2015-10-26 23:15:30", updated_at: "2015-10-26 23:15:30", relation: "nephew", member_id: 75, connection_sent_at: nil, connection_responded_at: nil, connect_send_limit: nil, connect_times_sent: nil, connected: nil, connect_type: nil, request_status: nil, connection_removed_at: nil>
[12] pry(#<RSpec::ExampleGroups::User>)> membership.family_tree
=> #<FamilyTree id: nil, name: "Ms. Milan Goldner", user_id: 1197, created_at: "2015-10-26 23:15:30", updated_at: "2015-10-26 23:15:30">

So even though the local variable membership is assigned properly, i.e. with the correct user and family_tree record, when I try to access it from the user's perspective - i.e. u1 it returns an empty array.

I think it has something to do with the fact that family_tree record is nil on my u1 object. Not sure how to deal with that though.


Solution

  • I think you don't need to use through: :family_tree, dependent: :destroy

    in

    User has_one :family_tree, dependent: :destroy has_many :memberships, through: :family_tree, dependent: :destroy

    since there is direct relationship between user and membership since you have a belongs_to :user in Membership

    Membership belongs_to :family_tree belongs_to :user belongs_to :member

    Your test is producing [] array when you are doing u2.memberships.where(relation: relation).pluck(:relation) since there is no family tree created for the second user.