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 Building the Friendship UI Creating the Friendship

Mark Lavelle
Mark Lavelle
2,910 Points

NoMethodError: undefined method `user_friendships' for nil:NilClass

I am having trouble with creating the friendship module. test is not recognising the user_friendships method in the create method.

Marks-MacBook-Pro:treebook Redeye$ ruby -Itest test/controllers/user_friendships_controller_test.rb
Run options: --seed 56989

# Running tests:

EE............

Finished tests in 0.229584s, 60.9799 tests/s, 74.0470 assertions/s.

  1) Error:
UserFriendshipsControllerTest#test: #create  with a valid friend_id should assign a friend object. :
NoMethodError: undefined method `user_friendships' for nil:NilClass
    app/controllers/user_friendships_controller.rb:19:in `create'
    test/controllers/user_friendships_controller_test.rb:93:in `block (3 levels) in <class:UserFriendshipsControllerTest>'

  2) Error:
UserFriendshipsControllerTest#test: #create  with a valid friend_id should assign a user_friendship object. :
NoMethodError: undefined method `user_friendships' for nil:NilClass
    app/controllers/user_friendships_controller.rb:19:in `create'
    test/controllers/user_friendships_controller_test.rb:93:in `block (3 levels) in <class:UserFriendshipsControllerTest>'

14 tests, 17 assertions, 0 failures, 2 errors, 0 skips

It is recognising it in the new method though. I have checked the server shell window for what is happening

the following is the log from the terminal shell

Started GET "/user_friendships/new?friend_id=marko" for 127.0.0.1 at 2014-02-28 11:31:21 +0000
Processing by UserFriendshipsController#new as HTML
  Parameters: {"friend_id"=>"marko"}
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 2 ORDER BY "users"."id" ASC LIMIT 1
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."profile_name" = 'marko' ORDER BY "users"."id" ASC LIMIT 1
  Rendered user_friendships/new.html.erb within layouts/application (2.1ms)
  Rendered layouts/_header.html.erb (0.4ms)
Completed 200 OK in 19ms (Views: 15.0ms | ActiveRecord: 0.5ms)


Started POST "/user_friendships" for 127.0.0.1 at 2014-02-28 11:31:24 +0000
Processing by UserFriendshipsController#create as HTML
  Parameters: {"utf8"=>"?", "authenticity_token"=>"r+Kgh/7SwbvIFJmCrLEPNBjIaTJkWa7EbRCVZXBYa2A=", "user_friendship"=>{"friend_id"=>"#<User:0x007fdac84e78e8>"}, "commit"=>"Yes, add Friend"}
Redirected to http://localhost:3000/
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)


Started GET "/" for 127.0.0.1 at 2014-02-28 11:31:24 +0000
Processing by StatusesController#index as HTML
  Status Load (0.3ms)  SELECT "statuses".* FROM "statuses"
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1  [["id", 1]]
  CACHE (0.0ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1  [["id", 1]]
  User Load (0.1ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1  [["id", 2]]
  CACHE (0.0ms)  SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1  [["id", 2]]
  Rendered statuses/index.html.erb within layouts/application (9.4ms)
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 2 ORDER BY "users"."id" ASC LIMIT 1
  Rendered layouts/_header.html.erb (1.4ms)
Completed 200 OK in 23ms (Views: 21.1ms | ActiveRecord: 0.8ms)

in particular it seems that the problem stems from here,

Started POST "/user_friendships" for 127.0.0.1 at 2014-02-28 11:31:24 +0000
Processing by UserFriendshipsController#create as HTML
  Parameters: {"utf8"=>"?", "authenticity_token"=>"r+Kgh/7SwbvIFJmCrLEPNBjIaTJkWa7EbRCVZXBYa2A=", "user_friendship"=>{"friend_id"=>"#<User:0x007fdac84e78e8>"}, "commit"=>"Yes, add Friend"}
Redirected to http://localhost:3000/
Completed 302 Found in 1ms (ActiveRecord: 0.0ms)

I am using rails 4 but have worked around the strong params as best i could. don't think that is what is causing problem. Tried the answer Jason gave on another thread for the same problem that involved adding .profile_name to the valid friend_id context but that has had no effect what so ever. the browser raises the else part of the method , i.e. it flashes an error and returns the root_path.

here is my User Friendships Controller

class UserFriendshipsController < ApplicationController
    before_filter :authenticate_user!, only: [:new]

    def new
        if params[:friend_id]
            @friend = User.where(profile_name: params[:friend_id]).first
            raise ActiveRecord::RecordNotFound if @friend.nil?
            @user_friendship = current_user.user_friendships.new(friend: @friend)
        else
            flash[:error] = "Friend required"
        end
    rescue ActiveRecord::RecordNotFound
        render file: 'public/404', status: :not_found
    end

    def create
        if params[:friend_id]
            @friend = User.where(profile_name: params[:friend_id]).first
            @user_friendship = current_user.user_friendships.build(friend: @friend)         
        else
            flash[:error] = "Friend required"
            redirect_to root_path
        end
    end
end

Oh and the test is the user friendships controller test

require 'test_helper'

class UserFriendshipsControllerTest < ActionController::TestCase

  context "#new" do     

      context "when not logged in" do
          should "redirect to the login page" do
            get :new
            assert_response :redirect
          end
      end

      context "when logged in" do
        setup do
          sign_in users(:mark)
        end

        should "get new page and return success" do
          get :new
          assert_response :success
        end

        should "set a flash error if the friend_id params is missing" do
          get :new, {}
          assert_equal "Friend required", flash[:error]
        end

        should "display the friend's name" do
          get :new, friend_id: users(:rea)
          assert_match /#{users(:rea).full_name}/, response.body
        end

        should "assign a new user friendship" do
          get :new, friend_id: users(:rea)
          assert assigns(:user_friendship)
        end

        should "assign a new user friendship to the correct friend" do
          get :new, friend_id: users(:rea)
          assert_equal users(:rea), assigns(:user_friendship).friend
        end

        should "assign a new user friendship to the currently logged in user" do
          get :new, friend_id: users(:rea)
          assert_equal users(:mark), assigns(:user_friendship).user
        end

        should "returns a 404 status if no friend is found" do
          get :new, friend_id: 'invalid'
          assert_response :not_found
        end

        should "ask if you really want to friend the user" do
          get :new, friend_id: users(:rea)
          assert_match /Do you really want to friend #{users(:rea).full_name}?/, response.body
        end
      end             
  end

  context "#create" do

    context "when not logged in" do
      should "redirect to the login page" do
        get :new
        assert_response :redirect
        assert_redirected_to login_path
      end
    end

    context "when logged in" do
      setup do
        sign_in users(:mark)
      end
    end

    context "with no friend_id" do
      setup do
        post :create
      end

      should "set the flash error" do
        assert !flash[:error].empty?
      end

      should "redirect to the site root path" do
         assert_redirected_to root_path
      end
    end

    context " with a valid friend_id" do
      setup do
        post :create, friend_id: users(:adam).profile_name
      end

      should "assign a friend object" do
        assert assigns(:friend)    
      end

      should "assign a user_friendship object" do
        assert assigns(:user_friendship)
      end
    end

  end
end

Do I need to add the create method to the before_filter to authenticate_user from devise
to access current_user method ? If I do that it raises a whole lot of errors.

I could go on adding code and error messages form the console but I think there is enough info there for someone smarter than me to figure out what I'm doing.

Thanks in advance and a pint on me in Dublin if you can help.

Cheers

Mark

Mark Lavelle
Mark Lavelle
2,910 Points

Eh... (sheepish sideways glance) remember ALWAYS CHECK FOR TYPOS I had one of the contexts out of context ( see what I did there Jason?? ) Unnested the contexts and read through the tests while re-watching Jason and found an extra end..

context "when logged in" do setup do sign_in users(:mark) end end <-- this one should not be there as the following tests don't have a logged in user if it <strong>is</strong> there

1 Answer

That error usually means that your calling the method "user_friendships" on a nil class. I.E. if you are calling --> @object.method_name and @object is nil, it will return this error message

Mark Lavelle
Mark Lavelle
2,910 Points

Thanks Jojo I was calling it on nothing as I had the test in the wrong place.