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

Nelly Nelly
Nelly Nelly
7,134 Points

can't run the users_controller_spec.rb

Hi again,

My scaffolding has generated different files compared to Jason's and now I am stuck again... Just in case, My git repo: https://github.com/knopfler81/odot/tree/user_auth

sample from Jason's version

  describe "GET new" do
    it "assigns a new user as @user" do
      get :new, {}, valid_session
     assigns(:user).should be_a_new(User)
    end
  end

sample from my version

  describe "GET #new" do
    it "assigns a new user as @user" do
      get :new, params: {}, session: valid_session
      expect(assigns(:user)).to be_a_new(User)
    end
  end

I don't know how to set the :valid_session to make my test pass

  let(:valid_session) {

     skip("I don't know what to put in there!!!!")
  }

my full file : users_controller_spec.rb

require 'rails_helper'

RSpec.describe UsersController, type: :controller do

  # This should return the minimal set of attributes required to create a valid
  # User. As you add validations to User, be sure to
  # adjust the attributes here as well.
  let(:valid_attributes) {{
      first_name:           "Jason",
      last_name:            "Seifer",
      email:                "jason@teamtreehouse.com",
      password:             "password12345",
      password_confirmation: "password12345"
    }}


  let(:invalid_attributes) {
    skip("Add a hash of attributes invalid for your model")
  }

  # This should return the minimal set of values that should be in the session
  # in order to pass any filters (e.g. authentication) defined in
  # UsersController. Be sure to keep this updated too.
  let(:valid_session) {

     skip("I don't know what to put in there!!!!")
  }

  describe "GET #new" do
    it "assigns a new user as @user" do
      get :new, params: {}, session: valid_session
      expect(assigns(:user)).to be_a_new(User)
    end
  end

  describe "GET #edit" do
    it "assigns the requested user as @user" do
      user = User.create! valid_attributes
      get :edit, params: {id: user.to_param}, session: valid_session
      expect(assigns(:user)).to eq(user)
    end
  end

  describe "POST #create" do
    context "with valid params" do
      it "creates a new User" do
        expect {
          post :create, params: {user: valid_attributes}, session: valid_session
        }.to change(User, :count).by(1)
      end

      it "assigns a newly created user as @user" do
        post :create, params: {user: valid_attributes}, session: valid_session
        expect(assigns(:user)).to be_a(User)
        expect(assigns(:user)).to be_persisted
      end

      it "redirects to the created user" do
        post :create, params: {user: valid_attributes}, session: valid_session
        expect(response).to redirect_to(User.last)
      end

      it "sets the session user_id to the created user" do
        post :create, params: {user: valid_attributes}, session: valid_session
        expect(session[:user_id]).to eq(User.find(email: valid_attributes["email"]).id)
      end
    end

    context "with invalid params" do
      it "assigns a newly created but unsaved user as @user" do
        post :create, params: {user: invalid_attributes}, session: valid_session
        expect(assigns(:user)).to be_a_new(User)
      end

      it "re-renders the 'new' template" do
        post :create, params: {user: invalid_attributes}, session: valid_session
        expect(response).to render_template("new")
      end
    end
  end

  describe "PUT #update" do
    context "with valid params" do
      let(:new_attributes) {
        skip("Add a hash of attributes valid for your model")
      }

      it "updates the requested user" do
        user = User.create! valid_attributes
        put :update, params: {id: user.to_param, user: new_attributes}, session: valid_session
        user.reload
        skip("Add assertions for updated state")
      end

      it "assigns the requested user as @user" do
        user = User.create! valid_attributes
        put :update, params: {id: user.to_param, user: valid_attributes}, session: valid_session
        expect(assigns(:user)).to eq(user)
      end

      it "redirects to the user" do
        user = User.create! valid_attributes
        put :update, params: {id: user.to_param, user: valid_attributes}, session: valid_session
        expect(response).to redirect_to(user)
      end
    end

    context "with invalid params" do
      it "assigns the user as @user" do
        user = User.create! valid_attributes
        put :update, params: {id: user.to_param, user: invalid_attributes}, session: valid_session
        expect(assigns(:user)).to eq(user)
      end

      it "re-renders the 'edit' template" do
        user = User.create! valid_attributes
        put :update, params: {id: user.to_param, user: invalid_attributes}, session: valid_session
        expect(response).to render_template("edit")
      end
    end
  end

  describe "DELETE #destroy" do
    it "destroys the requested user" do
      user = User.create! valid_attributes
      expect {
        delete :destroy, params: {id: user.to_param}, session: valid_session
      }.to change(User, :count).by(-1)
    end

    it "redirects to the users list" do
      user = User.create! valid_attributes
      delete :destroy, params: {id: user.to_param}, session: valid_session
      expect(response).to redirect_to(users_url)
    end
  end

end

19 Answers

Hi Nelly, You scaffolding is using a later version of RSpec (v 3) than the course which, I think used v.2. One effect of this is to change the assertions. For example:

require 'spec'

describe 'new RSpec syntax' do 
  it "uses the new assertion syntax" do
    expect(1 + 1).to eq(2)
  end

  it "uses the old syntax - now deprecated" do
    (1 + 1).should == 2 # moved away from 'should'
  end
end

In my ODOT code, the :valid_session test doesn't amount to much:

let(:valid_session) { {} }

describe "GET new" do 
  it "assigns a new user as @user" do
  .
  .

Try that and let me know how you get on.

I hope that helps!

Steve.

Nelly Nelly
Nelly Nelly
7,134 Points

Hello Steve,

if I leave

let(:valid_session){ {} } 

it fails

I believe like for :valid_attributes there is something to do but I can't figure out...

  let(:valid_attributes) {{
      first_name:           "Jason",
      last_name:            "Seifer",
      email:                "jason@teamtreehouse.com",
      password:             "password12345",
      password_confirmation: "password12345"
    }}

I think to create a valid session for an existing user you just need an email address and a password? Remember_me is optional?

let(:valid_session) {  
  { email:     "jason@teamtreehouse.com",
    password:  "password12345" }
}

Sorry, I've not touched this project in ages - I am rusty!

Steve.

Nelly Nelly
Nelly Nelly
7,134 Points

I tried earlier with this syntax which is I beleive the correct syntax two pairs or currly braces {{}}

  let!(:valid_session) {
  {  email:                "jason@teamtreehouse.com",
    password:             "password12345"}
  }

but I still have errors here are for exemple the two first: It seems that it ask for an id... but can't figure out how to set it :(

 1) UsersController GET #edit assigns the requested user as @user
     Failure/Error: get :edit, params: {id: user.to_param}, session: valid_session

     ActionController::UrlGenerationError:
       No route matches {:action=>"edit", :controller=>"users", :params=>{:id=>"2"}, :session=>{:email=>"jason@teamtreehouse.com", :password=>"password12345"}}
     # ./spec/controllers/users_controller_spec.rb:57:in `block (3 levels) in <top (required)>'

  2) UsersController POST #create with valid params creates a new User
     Failure/Error: params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation)

     ActionController::ParameterMissing:
       param is missing or the value is empty: user
     # ./app/controllers/users_controller.rb:63:in `user_params'
     # ./app/controllers/users_controller.rb:17:in `create'
     # ./spec/controllers/users_controller_spec.rb:66:in `block (5 levels) in <top (required)>'
     # ./spec/controllers/users_controller_spec.rb:65:in `block (4 levels) in <top (required)>'

Let's try the GET #edit thing first. And, yes, you're correct about the curly braces.

You have one line different to me:

get :edit, params: {id: user.to_param}, session: valid_session

I have a slightly different thing:

get :edit, { :id => user.to_param }, valid_session

I'm pretty sure they're basically the same thing - worth a try, though! My test is then in old format but does pretty much the same thing. The issue is that your controller doesn't have an edit route. I'm not sure why that would be ... what does typing rake routes in terminal give you?

The second issue, to do with POST, is failing because there's no instance of the User class. We need to figure out why not! Probably to do with the :valid_session thing too ...

Nelly Nelly
Nelly Nelly
7,134 Points

rake routes gives this

                  Prefix Verb   URI Pattern                                                 Controller#Action
                       users GET    /users(.:format)                                            users#index
                             POST   /users(.:format)                                            users#create
                    new_user GET    /users/new(.:format)                                        users#new
                   edit_user GET    /users/:id/edit(.:format)                                   users#edit
                        user GET    /users/:id(.:format)                                        users#show
                             PATCH  /users/:id(.:format)                                        users#update
                             PUT    /users/:id(.:format)                                        users#update
                             DELETE /users/:id(.:format)                                        users#destroy
               user_sessions POST   /user_sessions(.:format)                                    user_sessions#create
            new_user_session GET    /user_sessions/new(.:format)                                user_sessions#new
complete_todo_list_todo_item PATCH  /todo_lists/:todo_list_id/todo_items/:id/complete(.:format) todo_items#complete
        todo_list_todo_items GET    /todo_lists/:todo_list_id/todo_items(.:format)              todo_items#index
                             POST   /todo_lists/:todo_list_id/todo_items(.:format)              todo_items#create
     new_todo_list_todo_item GET    /todo_lists/:todo_list_id/todo_items/new(.:format)          todo_items#new
    edit_todo_list_todo_item GET    /todo_lists/:todo_list_id/todo_items/:id/edit(.:format)     todo_items#edit
         todo_list_todo_item GET    /todo_lists/:todo_list_id/todo_items/:id(.:format)          todo_items#show
                             PATCH  /todo_lists/:todo_list_id/todo_items/:id(.:format)          todo_items#update
                             PUT    /todo_lists/:todo_list_id/todo_items/:id(.:format)          todo_items#update
                             DELETE /todo_lists/:todo_list_id/todo_items/:id(.:format)          todo_items#destroy
                  todo_lists GET    /todo_lists(.:format)                                       todo_lists#index
                             POST   /todo_lists(.:format)                                       todo_lists#create
               new_todo_list GET    /todo_lists/new(.:format)                                   todo_lists#new
              edit_todo_list GET    /todo_lists/:id/edit(.:format)                              todo_lists#edit
                   todo_list GET    /todo_lists/:id(.:format)                                   todo_lists#show
                             PATCH  /todo_lists/:id(.:format)                                   todo_lists#update
                             PUT    /todo_lists/:id(.:format)                                   todo_lists#update
                             DELETE /todo_lists/:id(.:format)                                   todo_lists#destroy
                        root GET    /                                                           todo_lists#index

Try using hash rockets for the assignment:

let(:valid_attributes) { }
  "first_name" => "Jason", 
  "last_name" => "Seifer", ...

And the same with the session hash.

let(:valid_session) {  
  { "email" => "jason@teamtreehouse.com",
    "password" =>  "password12345" }
}

So, rake routes shows the user#edit route but states the access is of a certain URL. This is malformed, according to the error the test throws.

I'd start with changing the :edit code to:

get :edit, { :id => user.to_param }, valid_session

That might clean up the url formation? I hope!!

Nelly Nelly
Nelly Nelly
7,134 Points

Since you made me change this line

get :edit, { :id => user.to_param }, valid_session

This is green :D :D ( we are on the good way !!)

UsersController
  GET #new
    assigns a new user as @user
  GET #edit
    assigns the requested user as @user

the rest still red =(

  POST #create
    with valid params
      creates a new User (FAILED - 1)
      assigns a newly created user as @user (FAILED - 2)
      redirects to the created user (FAILED - 3)
      sets the session user_id to the created user (FAILED - 4)
    with invalid params
      assigns a newly created but unsaved user as @user (PENDING: Add a hash of attributes invalid for your model)
      re-renders the 'new' template (PENDING: Add a hash of attributes invalid for your model)
  PUT #update
    with valid params
      updates the requested user (PENDING: Add a hash of attributes valid for your model)
      assigns the requested user as @user (FAILED - 5)
      redirects to the user (FAILED - 6)
    with invalid params
      assigns the user as @user (PENDING: Add a hash of attributes invalid for your model)
      re-renders the 'edit' template (PENDING: Add a hash of attributes invalid for your model)
  DELETE #destroy
    destroys the requested user (FAILED - 7)
    redirects to the users list (FAILED - 8)

Pending: (Failures listed here are expected and do not affect your suite's status)

  1) UsersController POST #create with invalid params assigns a newly created but unsaved user as @user
     # Add a hash of attributes invalid for your model
     # ./spec/controllers/users_controller_spec.rb:87

  2) UsersController POST #create with invalid params re-renders the 'new' template
     # Add a hash of attributes invalid for your model
     # ./spec/controllers/users_controller_spec.rb:92

  3) UsersController PUT #update with valid params updates the requested user
     # Add a hash of attributes valid for your model
     # ./spec/controllers/users_controller_spec.rb:105

  4) UsersController PUT #update with invalid params assigns the user as @user
     # Add a hash of attributes invalid for your model
     # ./spec/controllers/users_controller_spec.rb:126

  5) UsersController PUT #update with invalid params re-renders the 'edit' template
     # Add a hash of attributes invalid for your model
     # ./spec/controllers/users_controller_spec.rb:132

This is progress ... let me look at those errors ... GET is working but POST is unhappy ... this might be a simple fix. crosses fingers

Nelly Nelly
Nelly Nelly
7,134 Points

Thank you so much for your help ! I reaaaaallly appreciate :)

In all your POST tests, change:

post :create, params: {user: valid_attributes}, session: valid_session

to just:

post :create, { :user => valid_attributes }, valid_session

Let's just do the first POST test first, see if that goes green.

So, change:

  describe "POST #create" do
    context "with valid params" do
      it "creates a new User" do
        expect {
          post :create, params: {user: valid_attributes}, session: valid_session
        }.to change(User, :count).by(1)
      end

to:

  describe "POST #create" do
    context "with valid params" do
      it "creates a new User" do
        expect {
          post :create, { :user => valid_attributes }, valid_session
        }.to change(User, :count).by(1)
      end

Just that one line ...

Nelly Nelly
Nelly Nelly
7,134 Points

I've changed this part too:

context "with invalid params" do
      it "assigns a newly created but unsaved user as @user" do
        post :create,  {:user => invalid_attributes}, valid_session
        expect(assigns(:user)).to be_a_new(User)
      end

      it "re-renders the 'new' template" do
        post :create,  {:user => invalid_attributes}, valid_session
        expect(response).to render_template("new")
      end
    end

I believe I have to change also put and delete

Yes, but you have POST and the invalid attributes first too. That needs a hash setting up for invalid atrributes, or just pass some in as a hash:

    context "with invalid params" do
      it "assigns a newly created but unsaved user as @user" do
        post :create, { user => { "first_name" => "invalid value" } }, valid_session
        expect(assigns(:user)).to be_a_new(User)
      end

      it "re-renders the 'new' template" do
        post :create, { user => { "first_name" => "invalid value" } }, valid_session
        expect(response).to render_template("new")
      end
    end

Sorry - that's what you did ... I was looking at two things at once!!!

Excellent - so, one-by-one change that line in each of the tests where it appears. See if there's any errors once you've done that. :smile:

Nelly Nelly
Nelly Nelly
7,134 Points

I will post once it's finished :smile:

Cool - I think it is fairly clear what needs changing now. There's a couple of skip commands to take out, but the user hash and session attributes just need to be simplified. It should work after all that!!

Nelly Nelly
Nelly Nelly
7,134 Points

sigh one is failing :(

1) UsersController POST #create with valid params sets the session user_id to the created user
     Failure/Error: expect (valid_session[:user_id]).to eq(User.find(email: valid_attributes["email"]).id)

     ActiveRecord::RecordNotFound:
       Couldn't find User with 'id'={:email=>nil}
     # ./spec/controllers/users_controller_spec.rb:87:in `block (4 levels) in <top (required)>'
  it "sets the session user_id to the created user" do
        post :create, { user: valid_attributes }, valid_session
        expect (valid_session[:user_id]).to eq(User.find(email: valid_attributes["email"]).id)
      end

So very close!!

Try using the find_by method on the User class, not the find method.

expect (valid_session[:user_id]).to eq(User.find_by(email: valid_attributes["email"]).id)

When you're not passing a straight :id to find something, use find_by else it looks for an instance id of { :email => nil } which is nonsense!!

That should work ... ?

Nelly Nelly
Nelly Nelly
7,134 Points

That's what I got with the update abow

1) UsersController POST #create with valid params sets the session user_id to the created user
     Failure/Error: params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, params[:id])

     ActionController::ParameterMissing:
       param is missing or the value is empty: user
     # ./app/controllers/users_controller.rb:63:in `user_params'
     # ./app/controllers/users_controller.rb:17:in `create'
     # ./spec/controllers/users_controller_spec.rb:86:in `block (4 levels) in <top (required)>'

My fault - I missed that you were using the wrong type of session so that threw an invalid user. Try changing valid_session to just session here:

expect (valid_session[:user_id]).to eq(User.find_by(email: valid_attributes["email"]).id)
 # change to 
expect (session[:user_id]).to eq(User.find_by(email: valid_attributes["email"]).id)

Sorry about that!

Nelly Nelly
Nelly Nelly
7,134 Points

you will hate me :sad:

Failures:

  1) UsersController POST #create with valid params sets the session user_id to the created user
     Failure/Error: expect (session[:user_id]).to eq(User.find_by(email: valid_attributes["email"]).id)

     NoMethodError:
       undefined method `id' for nil:NilClass
     # ./spec/controllers/users_controller_spec.rb:87:in `block (4 levels) in <top (required)>'

Dammit!! lol.

THat's going to bug me .... I've got to go out for a bit. Back later.

I'm wondering why we're using the sessions user, then comparing that to the valid_attributes. It sort of makes sense. Try changing ["email"] to [:email], just to be consistent with how you created the hash; it should make no difference at all.

Nelly Nelly
Nelly Nelly
7,134 Points

I really don't understand anything anymore lol I become nuts lol I believe we are comparing the user session to the valid_attributes to make sure that the user were well registred ( with the valid attributes...?

btw has you expected ther eis no difference

it "sets the session user_id to the created user" do
        post :create,{ user: valid_attributes }, valid_session
        expect (session[:user_id]).to eq(User.find_by(email: valid_attributes[:email]).id)
 end
Nelly Nelly
Nelly Nelly
7,134 Points

A f**** space.... between expect and ( session...) arggg I think I need a break now)

  it "sets the session user_id to the created user" do
        post :create,{ user: valid_attributes }, valid_session
        expect(session[:user_id]).to eq(User.find_by(email: valid_attributes[:email]).id)
      end

it's all green now !!

UsersController
  GET #new
    assigns a new user as @user
  GET #edit
    assigns the requested user as @user
  POST #create
    with valid params
      creates a new User
      assigns a newly created user as @user
      redirects to the created user
      sets the session user_id to the created user
    with invalid params
      assigns a newly created but unsaved user as @user
      re-renders the 'new' template
  PUT #update
    with valid params
      updates the requested user
      assigns the requested user as @user
      redirects to the user
    with invalid params
      assigns the user as @user
      re-renders the 'edit' template
  DELETE #destroy
    destroys the requested user
    redirects to the users list

Remember what I said about random spacing issues a little earlier; there you go. They are the worst things to spot! So, well done!!

Nelly Nelly
Nelly Nelly
7,134 Points

THANK YOU SO MUCH FOR YOUR PATIENCE AND YOUR HELP !!!

:+1: Hey - no problem! :+1:

Glad you got it fixed!!! :smile:

Shout if you need help with other Rails issues; you can @ mention me in here to get a direct response. Nelly Nelly <-- like that ...

Nelly Nelly
Nelly Nelly
7,134 Points

I will very soon thanks a lot ! I have a new issue.....

Have you opened a new post? Tag me if you have - happy to have a look if I can help!

:+1: