oneWorkingHeadphone
oneWorkingHeadphone

Reputation: 899

Railstutorial ActionView::Template::Error: undefined method `email' for nil:NilClass

I'm working through the Hartl tutorial for the second time only this time I'm trying to modify it for a personal project. Now I'm stumped as to why I can't get my test to pass (or the edit settings page to render). The issues is very similar to this question except the error is returning for email and not downcase and I'm using the default test suite and not Rspec.

Here is the error code:

ERROR["test_unsuccessful_edit", UsersEditTest, 0.7226080000109505]
 test_unsuccessful_edit#UsersEditTest (0.72s)
ActionView::Template::Error:         ActionView::Template::Error: undefined method `email' for nil:NilClass
            app/helpers/users_helper.rb:6:in `gravatar_for'
            app/views/users/edit.html.erb:8:in `_app_views_users_edit_html_erb___3727331653542369693_70276142435800'
            test/integration/users_edit_test.rb:11:in `block in <class:UsersEditTest>'

And each file referenced:

app/helpers/user_helper

module UsersHelper

  # Returns the Gravatar for the given user.
  def gravatar_for(user, options = { size: 80 })
    gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
    size = options[:size]
    gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
    image_tag(gravatar_url, alt: user.name, class: "gravatar")
  end
end

app/views/users/edit.html.erb

<% provide(:title, "Edit user") %>
<% provide(:button_text, 'Edit account') %>
<h1>Update your profile</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
    <div class="gravatar_edit">
      <%= gravatar_for @user %>
      <a href="http://gravatar.com/emails" target="_blank" rel="noopener noreferrer">change</a>
    </div>

    <%= render 'form' %>

  </div>
</div>

test/integration/users_edit_test.rb

require 'test_helper'

class UsersEditTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
  end

  test "unsuccessful edit" do
    log_in_as(@user)
    get edit_user_path(@user)
    assert_template 'users/edit'
    patch user_path(@user), params: { user: { name:  "",
                                              email: "foo@invalid",
                                              password:              "foo",
                                              password_confirmation: "bar" } }

    assert_template 'users/edit'
  end
end

And, because it was the issue in the other question, here is the relevant part of the user model. If I add '!' to the email.downcase method at the end, all the other tests that use email fail, but without it they all pass (except this one).

app/model/user.rb

class User < ApplicationRecord
  attr_accessor :remember_token
  before_save :downcase_email

...

private

    # Converts email to all lower-case
    def downcase_email
      self.email = email.downcase
    end

Here is the user controller

app/controllers/user_controller.rb
class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      log_in @user
      flash[:success] = 'Welcome to the Sample App'
      redirect_to @user
    else
      render 'new'
    end
  end

  def update
    @user = User.find(params[:id])
    if @user.update_attributes(user_params)
      # Handle a successful update.
    else
      render 'edit'
    end
  end

Upvotes: 0

Views: 2145

Answers (1)

theterminalguy
theterminalguy

Reputation: 1941

You will need to set @user instance variable in your UsersController#edit action. Like so

class UsersController < ApplicationController 
...
  def edit
    @user = User.find_by_id(params[:id]) 
  end 
...
end 

If this does not solve your problem, you can paste your UsersController code here that should help us solve your problems. However to make your code neater, you can set @user using a callback and call that callbacks on certain actions.

Upvotes: 2

Related Questions