user6124553
user6124553

Reputation:

I have an undefined method `name' for nil:NilClass, but I used to work

I have this undefined method "name", It used to work though... I don't know what I messed up... I need your help please...

index.html.slim

.container
  .row
    .col-xs-12
      h1.text-gray Tutorials 
      h4 Search by Title
      =form_tag tutos_path, :method => 'get' do 
        =text_field_tag :search, params[:search]
        =submit_tag "Search", class:'btn btn-default'

    .col-xs-12
      -if user_signed_in?
        = link_to "Create a tuto", new_tuto_path, class:"btn btn-success"


#tutos.transitions-enabled
  [email protected] do |tuto|
    .box.panel-default
      -if tuto.category.name == "Ruby"
        = link_to(image_tag("select/ruby.png"), tuto_path(tuto))
      -elsif tuto.category.name == "Rails 4"
        = link_to(image_tag("select/rails4.png"), tuto_path(tuto))
      -elsif tuto.category.name == "Rails 5"
        = link_to(image_tag("select/rails5.png"), tuto_path(tuto))
      -elsif tuto.category.name == "Heroku"
        = link_to(image_tag("select/heroku.png"), tuto_path(tuto))
      -elsif tuto.category.name == "AWS-Amazon"
        = link_to(image_tag("select/aws.png"), tuto_path(tuto))


      h3 = link_to tuto.title, tuto_path(tuto), class:"title-link"     
      h6 
        | Created by:
        span<>
        = tuto.user.full_name
      br
      span.glyphicon.glyphicon-heart
      span<>
      = tuto.get_upvotes.size
      br
      br

My categories are created in the console:

 Category Load (1.4ms)  SELECT "categories".* FROM "categories"
 => #<ActiveRecord::Relation [#<Category id: 1, name: "Ruby", created_at: "2016-09-26 09:03:17", updated_at: "2016-09-26 09:03:17">, #<Category id: 2, name: "Rails 4", created_at: "2016-09-26 09:03:25", updated_at: "2016-09-26 09:03:25">, #<Category id: 3, name: "Rails 5", created_at: "2016-09-26 09:03:30", updated_at: "2016-09-26 09:03:30">, #<Category id: 4, name: "Heroku", created_at: "2016-09-26 09:03:35", updated_at: "2016-09-26 09:03:35">, #<Category id: 5, name: "AWS-Amazon", created_at: "2016-09-26 09:03:43", updated_at: "2016-09-26 09:03:43">]>
2.3.1 :002 >

tutos_controller.rb

class TutosController < ApplicationController
  before_action :authenticate_user!, only: [:new, :create]
  before_action :set_tuto, only: [:show, :edit, :update, :destroy, :upvote]


  def index
    @tutos = Tuto.all.includes(:user && :category)
    @categories = Category.all
    keyword_search
  end

  def show
    @tuto = Tuto.find(params[:id])
    @user = User.all
  end


  def new
    @tuto = Tuto.new
  end

  def edit
  end

  def create

    @tuto = Tuto.new(tuto_params)
    @tuto.user_id = current_user.id

    respond_to do |format|
      if @tuto.save
        flash[:success] = "Test"
        format.html { redirect_to @tuto, notice: 'Tuto was successfully created.' }
        format.json { render :show, status: :created, location: @tuto }
      else
        format.html { render :new }
        format.json { render json: @tuto.errors, status: :unprocessable_entity }
      end
    end
  end


  def update
    respond_to do |format|
      if @tuto.update(tuto_params)
        format.html { redirect_to @tuto, notice: 'Tuto was successfully updated.' }
        format.json { render :show, status: :ok, location: @tuto }
      else
        format.html { render :edit }
        format.json { render json: @tuto.errors, status: :unprocessable_entity }
      end
    end
  end


  def destroy
    @tuto.destroy
    respond_to do |format|
      format.html { redirect_to tutos_url, notice: 'Tuto was successfully destroyed.' }
      format.json { head :no_content }
    end
  end


  def upvote
    @tuto.upvote_by current_user
    redirect_to :back
  end


  def keyword_search
   @tutos = Tuto.search(params[:search])
  end

  private

    def set_tuto
      @tuto = Tuto.find(params[:id])
    end

    def tuto_params
      params.require(:tuto).permit(:title, :content, :id, :user_id, :category_id)
    end
end

The schema

ActiveRecord::Schema.define(version: 20160920133801) do

  create_table "categories", force: :cascade do |t|
    t.string   "name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "tutos", force: :cascade do |t|
    t.datetime "created_at",  null: false
    t.datetime "updated_at",  null: false
    t.string   "title"
    t.text     "content"
    t.integer  "user_id"
    t.integer  "category_id"
  end

  add_index "tutos", ["user_id"], name: "index_tutos_on_user_id"

  create_table "users", force: :cascade do |t|
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip"
    t.string   "last_sign_in_ip"
    t.datetime "created_at",                          null: false
    t.datetime "updated_at",                          null: false
    t.string   "first_name"
    t.string   "last_name"
    t.boolean  "admin"
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true
  add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true

  create_table "votes", force: :cascade do |t|
    t.integer  "votable_id"
    t.string   "votable_type"
    t.integer  "voter_id"
    t.string   "voter_type"
    t.boolean  "vote_flag"
    t.string   "vote_scope"
    t.integer  "vote_weight"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  add_index "votes", ["votable_id", "votable_type", "vote_scope"], name: "index_votes_on_votable_id_and_votable_type_and_vote_scope"
  add_index "votes", ["voter_id", "voter_type", "vote_scope"], name: "index_votes_on_voter_id_and_voter_type_and_vote_scope"

end

tuto_model.rb

class Tuto < ActiveRecord::Base
  acts_as_votable
  belongs_to :user
  belongs_to :category
  validates :category_id, presence: true


  def self.search(search)
    if search
      where(["title LIKE ?","%#{search}%"])
    else
      all
    end
  end
end

category_model.rb

class Category < ActiveRecord::Base
  has_many :tutos
end

edit

this is the error i have with deepak's suggestion, ( BTW I really like the refactoing he suggested!!)

index.html.slim:29: syntax error, unexpected ';', expecting ')' ...temple_html_pretty1)))).to_s)); ... ^

Extracted source (around line #29):
27
28
29
30
31
32

  [email protected] do |tuto|
    .box.panel-default
      = link_to image_tag(image_by_category(tuto.category.try(:name)), tuto_path(tuto)


      h3 = link_to tuto.title, tuto_path(tuto), class:"title-link"  

Upvotes: 2

Views: 262

Answers (3)

Deepak Mahakale
Deepak Mahakale

Reputation: 23661

One of the category is nil that's why you are getting

undefined method "name" for nil:NilClass

Use try

index.html.slim

[email protected] do |tuto|
  .box.panel-default
    -if tuto.category.try(:name) == "Ruby"
      = link_to(image_tag("select/ruby.png"), tuto_path(tuto))
    -elsif tuto.category.try(:name) == "Rails 4"
      = link_to(image_tag("select/rails4.png"), tuto_path(tuto))
    -elsif tuto.category.try(:name) == "Rails 5"
      = link_to(image_tag("select/rails5.png"), tuto_path(tuto))
    -elsif tuto.category.try(:name) == "Heroku"
      = link_to(image_tag("select/heroku.png"), tuto_path(tuto))
    -elsif tuto.category.try(:name) == "AWS-Amazon"
      = link_to(image_tag("select/aws.png"), tuto_path(tuto))

Also I will suggest to make use of helper method in your code

index.html.slim

[email protected] do |tuto|
  .box.panel-default
    = link_to image_tag(image_by_category(tuto.category.try(:name))), tuto_path(tuto)

application_helper.rb

def image_by_category(name)
  images = {
    "Ruby" => "select/ruby.png",
    "Rails 4" => "select/rails4.png",
    "Rails 5" => "select/rails5.png",
    "Heroku" => "select/heroku.png",
    "AWS-Amazon" => "select/aws.png"
  }
  images[name]
end

Upvotes: 2

Sravan
Sravan

Reputation: 18647

In this @tutos loop, one of your categories is not present or nil, so name method is not present for nil and throwing you an error, for this, you can solve it in two ways.

1) check if category is present at the starting of the loop, if present, then only go in,

[email protected] do |tuto|
    .box.panel-default
    -if tuto.category.present?
        -if tuto.category.name == "Ruby"
        = link_to(image_tag("select/ruby.png"), tuto_path(tuto))
        -elsif tuto.category.name == "Rails 4"
        = link_to(image_tag("select/rails4.png"), tuto_path(tuto))
        -elsif tuto.category.name == "Rails 5"
        = link_to(image_tag("select/rails5.png"), tuto_path(tuto))
        -elsif tuto.category.name == "Heroku"
        = link_to(image_tag("select/heroku.png"), tuto_path(tuto))
        -elsif tuto.category.name == "AWS-Amazon"
        = link_to(image_tag("select/aws.png"), tuto_path(tuto))

2) Use try which continues execution without checking the error

[email protected] do |tuto|
    .box.panel-default
      -if tuto.try(:category).try(:name) == "Ruby"
        = link_to(image_tag("select/ruby.png"), tuto_path(tuto))
      -elsif tuto.try(:category).try(:name) == "Rails 4"
        = link_to(image_tag("select/rails4.png"), tuto_path(tuto))
      -elsif tuto.try(:category).try(:name) == "Rails 5"
        = link_to(image_tag("select/rails5.png"), tuto_path(tuto))
      -elsif tuto.try(:category).try(:name) == "Heroku"
        = link_to(image_tag("select/heroku.png"), tuto_path(tuto))
      -elsif tuto.try(:category).try(:name) == "AWS-Amazon"
        = link_to(image_tag("select/aws.png"), tuto_path(tuto))        

Upvotes: 1

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230336

Tuto.all.includes(:user && :category)

Should be

Tuto.all.includes(:user, :category)

Upvotes: 1

Related Questions