Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Ruby Building Social Features in Ruby on Rails Adding State Setting Up The State Machine

Nelly Nelly
Nelly Nelly
7,134 Points

setting has_many through with conditions. didn't work

Hi everyone !

I am using rails 4 and, I found a part of my response in @kevinkenger's post... but I'ma still having test faillures.... Any help would be welcome !

And here is my git repo https://github.com/knopfler81/treebook/tree/tree_house_next_step

this is my user.rb model

  has_many :statuses
  has_many :user_friendships

  has_many :friends,
                -> { where(user_friendships: { state: "accepted"}) },
                    through: :user_friendships


  has_many :pending_friends,
              -> { where user_friendships: { state: "pending" } },
                 through: :user_friendships,
                 source: :friend

the naughty failures

  1) Failure:
UserFriendshipTest#test_: #accept! should include the friend in the list of friends.  [test/models/user_friendship_test.rb:58]:
Expected false to be truthy.


  2) Failure:
UserFriendshipTest#test_that_creating_a_friendship_based_on_user_id_and_friend_id_works [test/models/user_friendship_test.rb:15]:
Expected false to be truthy.

11 runs, 10 assertions, 2 failures, 0 errors, 0 skips

The UserFriendship Model

class UserFriendship < ActiveRecord::Base
  belongs_to :user
  belongs_to :friend, class_name: 'User', foreign_key: "friend_id"

  state_machine :state, initial: :pending do
    after_transition on: :accept, do: :send_acceptance_email

    state :requested

    event :accept do
      transition any => :accepted
    end
  end

  def self.request(user1,user2)
    transaction do
      friendship1 = create!(user: user1, friend: user2, state: "pending")
      friendship2 = create!(user: user2, friend: user1, state: "requested")

      friendship1.send_request_email
      friendship1
    end
  end

  def send_request_email
    UserNotifier.friend_requested(id).deliver_now
  end

  def send_acceptance_email
     UserNotifier.friend_request_accepted(id).deliver_now
  end
end

the user friendship test

require 'test_helper'

class UserFriendshipTest < ActiveSupport::TestCase
  should belong_to(:user)
  should belong_to(:friend)

  test "that creating a friendship works without raising an exception" do
    assert_nothing_raised do
      UserFriendship.create user: users(:jason), friend: users(:mike)
    end
  end

  test "that creating a friendship based on user id and friend id works" do
    UserFriendship.create user_id: users(:jason).id, friend_id: users(:mike).id
    assert users(:jason).pending_friends.include?(users(:mike))
  end

  context "a new instance" do
    setup do
      @user_friendship = UserFriendship.new user: users(:jason), friend: users(:mike)
    end

    should "have a pending state" do
      assert_equal 'pending', @user_friendship.state
    end
  end

  context "#send_request_email" do
    setup do
      @user_friendship = UserFriendship.create user: users(:jason), friend: users(:mike)
    end
    should "send an email" do
      assert_difference 'ActionMailer::Base.deliveries.size', 1 do
        @user_friendship.send_request_email
      end
    end
  end

  context "#accept!" do
    setup do
      @user_friendship = UserFriendship.create user: users(:jason), friend: users(:mike)
    end

    should "set the state to accepted" do
      @user_friendship.accept!
      assert_equal "accepted", @user_friendship.state
    end

    should "send an acceptance email" do
      assert_difference 'ActionMailer::Base.deliveries.size', 1 do
        @user_friendship.accept!
      end
    end

    should "include the friend in the list of friends" do
      @user_friendship.accept!
      users(:jason).friends.reload
      assert users(:jason).friends.include?(users(:mike))
    end
  end

  context".request" do
    should "Create two user friendships" do
      assert_difference 'UserFriendship.count', 2 do
        UserFriendship.request(users(:jason),users(:mike))
      end
    end

    should "send a friend request email" do
      assert_difference 'ActionMailer::Base.deliveries.size', 1 do
        UserFriendship.request(users(:jason),users(:mike))
      end
    end
  end
end

Steve Hunter ? sorry that's me again :cry:

I've just cloned your repo - running bundler now - I'll shout you on Skype.

1 Answer

Nelly Nelly
Nelly Nelly
7,134 Points

needed to add a gem to make state_machines works

gem 'state_machines'
gem 'state_machines-activerecord'

updated this

  has_many :user_friendships
  has_many :friends,-> { where(user_friendships: { state: "accepted"}) }, through: :user_friendships
  has_many :pending_user_friendships, -> { where  state: "pending"  }, class_name: 'UserFriendship', foreign_key: :user_id
  has_many :pending_friends, through: :pending_user_friendships, source: :friend