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

Ep:What is a Join Table? Test Failure

As per the video I have the following test:

test "should create status when for the current user when logged in" do
    sign_in users(:jason)

    assert_difference('Status.count') do
      post :create, status: {content:@status.content, user_id: users(:jim).id}
    end
    assert_redirected_to status_path(assigns(:status))
    assert_equal assigns(:status).user_id, users(:jason).id
  end

I have updated my statuses_controller to the following:

def create
    @status = current_user.statuses.new(params[:status])

    respond_to do |format|
      if @status.save
        format.html { redirect_to @status, notice: 'Status was successfully created.' }
        format.json { render json: @status, status: :created, location: @status }
      else
        format.html { render action: "new" }
        format.json { render json: @status.errors, status: :unprocessable_entity }
      end
    end
  end

And I still get the following failure:

  1) Failure:     test_should_create_status_when_for_the_current_user_when_logged_in(StatusesContr    ollerTest) [test/functional/statuses_con
troller_test.rb:51]:
<1027431151> expected but was
<149087659>.

I have removed the user select box from the _form.html so only the current_user can post their own status and it works. Problem is the test still doesn't pass.

Any help appreciated

24 Answers

Frederic TETARD
Frederic TETARD
1,970 Points

I Fix the issue for me by putting

  post :create, status: { content: @status.content, user_id: @status.user.id }

instead of

 post :create, status: { content: @status.conten }

In your test you are signing in the user "Jason", but are posting with the user "Jim" and then you are trying to assert that you will be redirected to the status' path and that it's Jasons, but the status isnt being saved because a user that isnt signed in is trying to post it. (So technically your test is working correctly) You need to post with "Jason" if you are asserting that it's Jason's post.

should be

post :create, status: {content:@status.content, user_id: users(:jason).id}

Let me know if this works. I am not entirely sure if my logic is correct, but it makes sense that that is your issue.

Thanks for the help Riley. Your logic is correct. So I've updated the test as follows:

test "should create status when for the current user when logged in" do
    sign_in users(:jason)

    assert_difference('Status.count') do
      post :create, status: {content:@status.content}
    end
    assert_redirected_to status_path(assigns(:status))
    assert_equal assigns(:status).user_id, users(:jason).id
  end

Now I'm testing: a) is the status count updated when Jason posts a status b) If I post a status I am preperly redirected c) If I'm logged in as Jason my status is associated with Jason's id

Good but I'm no longer testing if I can post a status for Jason when I'm logged in as Jim. I think by modifying the _form.html that this is no longer possible to do but I'm curious if there's a test to prove it.

Also, still doesn't explain how Jason get's a positive assertion for

assert_equal assigns(:status).user_id, users(:jason).id" 

In the "What is Join Table" lesson his code matches the test in my first post????

Editing the _form.html.erb does not change the ability to perform the action, which is what the lesson is testing for. The changes you made to the statuses_controller.rb ensure that only the logged in user can post a status from their account by auto selecting the signed in user when the status is created, and therefor that form field isnt necessary/would create a save error anyway.

In your statuses_controller.rb have you completed all the code in the lesson, such as the update? it should be working for you as it appears you have all the same code as I have in mine, and All my tests are passing. Here is some of my code

<pre><code> test "should create status when logged in" do sign_in users(:riley)

assert_difference('Status.count') do
  post :create, status: { content: @status.content }
end

assert_redirected_to status_path(assigns(:status))

end

test "should create status for the current user when logged in" do sign_in users(:riley)

assert_difference('Status.count') do
  post :create, status: { content: @status.content, user_id: users(:john).id }
end

assert_redirected_to status_path(assigns(:status))
assert_equal assigns(:status).user_id, users(:riley).id

end </code></pre> Statuses Controller: <pre><code> def update @status = current_user.statuses.find(params[:id]) if params[:status] && params[:status].has_key?(:user_id) params[:status].delete(:user_id) end </code></pre> <pre><code> def create @status = current_user.statuses.new(params[:status]) </code></pre>

My code looks identical to yours:

statuses_controller.rb

 def create
    @status = current_user.statuses.new(params[:status])

    respond_to do |format|
      if @status.save
        format.html { redirect_to @status, notice: 'Status was successfully created.' }
        format.json { render json: @status, status: :created, location: @status }
      else
        format.html { render action: "new" }
        format.json { render json: @status.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    @status = current_user.statuses.find(params[:id])

    if params[:status] && params[:status].has_key?(:user_id)
      params[:status].delete(:user_id) 
    end

    respond_to do |format|
      if @status.update_attributes(params[:status])
        format.html { redirect_to @status, notice: 'Status was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @status.errors, status: :unprocessable_entity }
      end
    end
  end

statuses_controller_test.rb

test "should create status when for the current user when logged in" do
    sign_in users(:jason)

    assert_difference('Status.count') do
      post :create, status: {content:@status.content, user_id: users(:jim).id}
    end
    assert_redirected_to status_path(assigns(:status))
    assert_equal assigns(:status).user_id, users(:jason).id
  end

  test "should update status for the current user when logged in" do
    sign_in users(:jason)
    put :update, id: @status, status: {content: @status.content, user_id: users(:jim).id}
    assert_redirected_to status_path(assigns(:status))
    assert_equal assigns(:status).user_id, users(:jason).id
  end

But I still get a failure

  1) Failure:
 test_should_create_status_when_for_the_current_user_when_logged_in(StatusesContr    ollerTest) [test/functional/statuses_con
troller_test.rb:51]:
<1027431151> expected but was
<149087659>.

NOTE: when I test

assert_equal assigns(:status).user_id, users(:jim).id

I don't get any failure. Which leads me to believe Jim is able to post for Jason. But this shouldn't be possible because of the scope change in the statuses_controller.rb

Matthew - re-add the drop-down field to your form, boot the server and try it, you'll probably find that it is causing an error. I've had an almost identical problem as this and I think the problem is with the devise object current_user. A few days ago (though I notice this has now been updated) on their GitHub the build was marked as 'failing', so I wonder if there's some sort of issue there.

Testing the current_user using a different model or a view on my app showed it was sporadically available to models, but for some reason always accessible to views. Not sure why.

I've re-added the drop-down menu. If I post a new status without selecting a name from the drop-down the app uses the logged in user - Jason. However, I can still post as Jim when I'm signed in as Jason (even with the proper scope change in the controller).

But when I try to edit one of Jim's statuses logged in as Jason, I get a Controller Exception (i.e. the desired response).

Couldn't find Status with id=2 [WHERE "statuses"."user_id" = 3]

Like you said Alex it seems like current_user helper is working sporadically....

In that case maybe the solution is a bundle install? Presumably that will download and update the devise gem....?

Jason Seifer
STAFF
Jason Seifer
Treehouse Guest Teacher

Hi Matthew, the reason that error is coming up is because the update action is trying to find the status based on the user scope. The status doesn't exist scoped to the current user which is why the error is thrown. We haven't gotten to disabling the edit form for other user's statuses yet.

Thanks for the reply Jason. I follow you on why I'm getting error on the update action. I believe that's the response we're looking for.

The problem I'm having is that I'm still able to create a status for another user even with it properly scoped in the create method.

Doug Macklin
PLUS
Doug Macklin
Courses Plus Student 5,453 Points

This thread got sidetracked, but I have the same problem as the initial post (which hasn't been solved). Let me break it down:

First, at 4:01 in the video, Jason gets two failures, but I only get the first one (no error about Status.count not changing).

Ignoring that for the time being, I followed the video's advice to change line 45 in statuses_controller.rb to:

@status = current_user.statuses.new(params[:status])

At 5:00, Jason runs the test again and it passes (no failures). When I run the test again, I still have the same failure as before:

  1) Failure:
test_should_create_status_for_the_current_user_when_signed_in(StatusesControllerTest) [test/functional/statuses_controller_test.rb:50]:
<855667630> expected but was
<902541635>.

In other words, this assertion on line 50 fails for me, but passes for Jason in the video:

assert_equal assigns(:status).user_id, users(:jason).id

That is, the test:

test "should create status for the current user when signed in" do
  sign_in users(:jason)

  assert_difference('Status.count') do
    post :create, status: { content: @status.content, user_id: users(:jim).id }
  end

  assert_redirected_to status_path(assigns(:status))
  assert_equal assigns(:status).user_id, users(:jason).id
end

is failing for me. This means the signed in user (Jason), is able to call the Statuses Controller create action and pass a status with Jim's id, but even though it should ignore Jim's id and post the status under the signed in user (Jason), it posts the status as Jim.

Matthew, if you ever figured this out, let me know. Otherwise, if anyone can explain why I'm not getting the same behavior as Jason in the video, that would be greatly appreciated.

P.S. I'm using Rails 3.2.1 and Ruby 1.9.3p392. Does anyone know what they are using in the video? If they use older versions, is it possible that a Ruby or Rails update changed the behavior to cause this issue? If so, could someone explain how I need to change the code to make this test pass?

Jason Seifer
STAFF
Jason Seifer
Treehouse Guest Teacher

Hey Doug, that's pretty strange. Would you mind zipping up your code and emailing it to help@teamtreehouse.com so I can take a look?

Doug Macklin
PLUS
Doug Macklin
Courses Plus Student 5,453 Points

Follow up:

I looked into this some more and noticed that you guys have the line:

attr_accessible :content, :user_id

in models/status.rb, which was initially:

attr_accessible :content, :name

way back when you first generated the status model.

I, on the other hand, don't have any attr_accessible line in the status.rb file (I think it either wasn't there when I initially generated the status model, or it got deleted later, possibly when I removed the name attribute from the status model). However, if I add in that line, I still get the same failed test as before, and I also get this error:

ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: id, created_at, updated_at

in test_should_create_status_when_signed_in and test_should_update_status_when_signed_in. I think I understand the mass assignment error, but now I'm wondering why you guys didn't get that error in the video since id, created_at, and updated_at aren't in your attr_accessible either. Regardless, adding the attr_accessible line only introduced these mass assignment errors; as mentioned, it did not fix the failing test (so I have removed the line).

Moreover, wouldn't you not want :user_id in your attr_accessible to prevent people from modifying the user_id of a status?

Update: I figured out that you guys are using Rails 3.2.6. As mentioned, I've been using Rails 3.2.1. I changed my Gemfile to use 3.2.6, and the test passes (though if I add in the attr_accessible line I still get the mass assignment errors, so I'm still confused why you guys don't get those errors). Any idea what changes in Rails cause this (only the patch version changed, not the major or minor version)?

Jason Seifer
STAFF
Jason Seifer
Treehouse Guest Teacher

Hey Doug,

Rails 3.2.1 is a bit old, it would be best to stay with the most current version of rails 3.2.x, or the version the videos are using.

You're right in that you wouldn't want user_id in attr_accessible to prevent people from modifying it. We fix that later on in the lessons. However, in my opinion, it makes it much easier to learn the concepts by getting something working quickly and then modifying it later. Regarding the created_at, updated_at, and id fields -- those are handled by rails automatically.

As far as why things are different from the point releases -- the rails core team will do security updates for minor versions of point releases. In the case of what we're seeing, requiring attr_accessible was a decision made in between point releases for enhanced security.

Hi Jason,

I am also having difficulty with the same video.

I get the two failures that you do:

  1) Failure:
test_should_post_status_for_the_current_user_when_logged_in(StatusesControllerTest[test/functional/statuses_controller_test.rb:50]:
<975247844> expected but was
<645198450>.

  2) Failure:
test_should_post_status_when_logged_in(StatusesControllerTest) [test/functional/statuses_controller_test.rb:35]:
"Status.count" didn't change by 1.
<4> expected but was
<3>.

But when I make the fix to statuses_controller.rb, I still have this error:

  1) Failure:
test_should_post_status_for_the_current_user_when_logged_in(StatusesControllerTest) [test/functional/statuses_controller_test.rb:50]:
<975247844> expected but was
<645198450>.

I was using Rails 3.2.1, but I upgraded to Rails 3.2.13 and I still have this issue.

OK. I fixed the problem.

I had initially just run 'gem install rails' on the command line, in order to update Rails.

But it seems that I also needed to change the actual rails version in my Gemfile and then run 'bundle update'.

Jason Seifer
STAFF
Jason Seifer
Treehouse Guest Teacher

Great work, Mark! Let us know if you have any more problems.

Itay Banner
Itay Banner
1,922 Points

Hi Jason,

Sorry but this is still an issue for me. I have the same symptoms as Mark Swan here, but I'm on the latest rails version (3.2.13). What's going on?

Jason Seifer
STAFF
Jason Seifer
Treehouse Guest Teacher

I'm not sure, Itay Banner . Can you email your code to help@teamtreehouse.com and we'll try and get it sorted out?

Itay Banner
Itay Banner
1,922 Points

I feel so moronic. My problem was on that line at the end of the test:

assert_equal assigns(:status).user_id, users(:jason).id

Where it says :jason (The current_user) I had the other user.... :-/ Thanks, @Jason Seifer for noticing that.

Having said that, I'd really urge you to make all the params[:status] business clearer. I can't remember where earlier you explained how this works, and the only reason my tests are now passing is because I successfully copied the code I saw in the video...

Frederic TETARD
Frederic TETARD
1,970 Points

I Fix the issue for me by putting

  post :create, status: { content: @status.content, user_id: @status.user.id }

instead of

 post :create, status: { content: @status.conten }