ekremkaraca
ekremkaraca

Reputation: 1449

undefined method error for instance variables in rails4 app

I was practising one of tutorials from a book. In this tutorial; all values from a few models were needed to be shown in some views. These instance variables were defined under sidebar_values method in application_controller.rb:

helper_method :sidebar_values

def sidebar_values
    @food_prefs = FoodPreference.all
    @food_types = FoodType.all
    @cuisines = Cuisine.all
end

Here is the part of the application.html.erb:

            <div class="col-lg-2">
                <div class="panel panel-primary" id="panels">
                    <div class="panel-heading">
                        Food Preferences
                    </div>
                    <% @food_prefs.each do |p| %> #42, error begins here
                        <p><%= p.name %></p>
                    <% end %>
                </div>
                <div class="panel panel-primary" id="panels">
                    <div class="panel-heading">
                        Food Types
                    </div>
                    <% @food_types.each do |t| %>
                        <p><%= t.name %></p>
                    <% end %>
                </div>
                <div class="panel panel-primary" id="panels">
                    <div class="panel-heading">
                        Cuisines
                    </div>
                    <% @cuisines.each do |c| %>
                        <p><%= c.name %></p>
                    <% end %>
                </div>
            </div> 

When I was trying to call these variables in a view, it throws error like this:

NoMethodError - undefined method `each' for nil:NilClass:
    app/views/layouts/application.html.erb:42:in `_app_views_layouts_application_html_erb___4138475832854219665_70001190164060'

Values in these variables aren't nil, however I was unable to call these variables from any view.

Upvotes: 0

Views: 1203

Answers (2)

Wally Ali
Wally Ali

Reputation: 2508

The reason why you are getting undefined method 'each' for nil:NilClass: on <% @food_prefs.each do |p| %> is because @food_prefs variable is nil. you are calling a method: each on a nil variable: @food_prefs. basically, if you open a rails console and query FoodPreference.count, it would return zero count. To get past this, create an instance of this class in the database so your count is no longer zero.

Or:

wrap around it an if statement. something like this:

<% if @food_prefs %>
  <% @food_prefs.each do |p| %> 
     <p><%= p.name %></p>
  <% end %>
<% end %>

you can remove this if statement later when you are sure your @food_prefs is no longer nil

How to define variables in a helper method:

though you may not need to define helper method in this case, you define them inside the files in your Helper folder. it's a straight forward ruby. just create methods that you can call inside your views. unlike the controller methods, you don't need the @ symbol. methods created inside your helpers are available in your views.

Upvotes: 0

MrYoshiji
MrYoshiji

Reputation: 54882

I know you are following a tutorial, but I think there is something missing:

# application_controller.rb
before_filter :sidebar_values

def sidebar_values
  @food_prefs = FoodPreference.all
  @food_types = FoodType.all
  @cuisines = Cuisine.all
end

This before_filter :sidebar_values will call the method sidebar_values on each action called. You can specify only/except options to filter a little bit the affected actions:

before_filter :sidebar_values, except: [:login, :logout]

Also, I would use a better name for this method, something like set_sidebar_variables since it is setting instance variables for the sidebar.

As I explained in the comments, I don't think you need to make it a helper method, IMO helper_method :sidebar_values can be removed.


Another thing is that there is not limit on your SQL queries, you just query all of the 3 models. This is not good in long-term. What if you have hundreds of Cuisines, FoodTypes and FoodPrefs ? I would add a .limit(x) to prevent from this case to happen:

def sidebar_values
  @food_prefs = FoodPreference.limit(10)
  @food_types = FoodType.limit(10)
  @cuisines = Cuisine.all
end

Upvotes: 3

Related Questions