kypalmer
kypalmer

Reputation: 464

undefined method error using an if conditional statement

I have a helper that checks if a user is signed in or not:

def signed_in?
  !current_user.nil?
end

I also have a helper that allows views and controllers to access the user object by checking the session:

def current_user
  @current_user ||= User.find_by_session(session[:user_id])
end

In one of my controllers, it works fine to pull up the user object

  def index
    @households = current_user.households.all
    @household = current_user.households.build

    respond_to do |format|
      format.html
      format.xml { render xml: @households }
    end
  end

The other controller, however, chokes on the current_user helper when it tries to call the households relation:

def home
  @households = current_user.households.all
  @household = current_user.households.build

  respond_to do |format|
    format.html
    format.xml { render xml: @households }
  end
end

The error:

undefined method `households' for nil:NilClass

I'm pretty stumped and could not find any posts related to this specific subject. I'm new to rails though. Am I asking this question in the wrong way?

Thanks in advance.

Upvotes: 0

Views: 763

Answers (4)

kypalmer
kypalmer

Reputation: 464

I hate to jump on here and answer my own question, but I had trouble with this for so long that I want anyone having the same problem to be able to figure this one out. This turned out to be a mixture of many of the answers on this page as well as Michael Hartl's tutorial book. I was using helper methods, but had not included the helpers in application_controller.rb:

class ApplicationController < ActionController::Base
  include ControllerAuthentication
  include SessionsHelper
...

I also was verifying that a user was signed in to display them dynamic content in my view home.html.erb:

<% if signed_in? %>
  <!-- show the user dashboard -->
...

But I had no such verification on the controller static_pages_controller.rb:

def home
  if signed_in?
  @households = current_user.households.all 
  @household  = current_user.households.build 
end

Because of all of this, the error:

undefined method `households' for nil:NilClass

was thrown continually while a user was not signed in and was trying to visit the root_path. In other cases I could have redirected, but I wanted the user to see dynamic content on the home page if they were logged in and a static landing page if they were not.

Thanks everyone for the help!

Upvotes: 0

Luke Mueller
Luke Mueller

Reputation: 263

Might have just spotted why your current_user method is returning nil. Your searching by session not by ID. Try this:

def current_user
  @current_user ||= User.find(session[:user_id])
end

OR if you want to be more explicit:

def current_user
  @current_user ||= User.find_by_id(session[:user_id])
end

Upvotes: 1

Luke Mueller
Luke Mueller

Reputation: 263

The problem isn't that the current_user helper method is unavailable to the second controller, it's that your current_user method is not finding a user and returning nil. Then your attempting to call the households method on the returned nil object.

If the current_user method was not available in that controller you would see an error message such as:

undefined local variable or method `current_user' for #<YourController:0x1057870e8>

This means you have a flaw in the flow of your logic. Either the session parameter hasn't been set yet by the time it hits that method, or it was set but to a user_id that doesn't exist.

Try adding:

def home
  @households = (logged_in? ? current_user.households.all : nil)
  @household  = (logged_in? ? current_user.households.build : nil)

  respond_to do |format|
    format.html
    format.xml { render xml: @households }
  end
end

Replacing nil with whatever your fallback data should be.

Upvotes: 1

megas
megas

Reputation: 21791

Try to include module into your second controller.

For example, helper module looks like this:

module UserHelper
  def current_user
    @current_user ||= User.find_by_session(session[:user_id])
  end
end

Then include it into your controller:

class YourController < ApplicationController
  include UserHelper

  def home
    @households = current_user.households.all
    @household = current_user.households.build

    respond_to do |format|
      format.html
      format.xml { render xml: @households }
    end
  end
end

Upvotes: 1

Related Questions