ruby-on-railsnomethoderror

NoMethodError in Products#index


I'm getting NoMethodError for this line <%= link_to product.category.name, category_path(product.category) %> which are in products_path/index. I'm not sure what's wrong, so asking for help. Thank for any help!

My code

products_controller.rb

  class ProductsController < ApplicationController
  before_action :set_product, only: [:show, :edit, :update, :destroy]
  before_action :authenticate_user!, except: [:index, :show]

  def index
    @products = Product.all
  end

  # GET /products/1
  def show
    @comments = @product.comments.order("created_at DESC").paginate(:page => params[:page], :per_page => 5)
  end

  # GET /products/new
  def new
    @product = Product.new
    @categories = Category.all.map{|c| [ c.name, c.id ] }
  end

  # GET /products/1/edit
  def edit
    @categories = Category.all.map{|c| [ c.name, c.id ] }
  end

  # POST /products
  def create
    @product = Product.new(product_params)
    @product.category_id = params[:category_id] 

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

  # PATCH/PUT /products/1
  def update
    @product.category_id = params[:category_id]
    respond_to do |format|
      if @product.update(product_params)
        format.html { redirect_to @product, notice: 'Product was successfully updated.' }
        format.json { render :show, status: :ok, location: @product }
      else
        format.html { render :edit }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /products/1
  def destroy
    @product.destroy
    respond_to do |format|
      format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_product
      @product = Product.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def product_params
      params.require(:product).permit(:name, :description, :image_url, :color, :price, :year_of_manufacture)
    end
  end

categories_controller.rb

  class CategoriesController < ApplicationController
  before_action :set_category, only: [:show, :edit, :update, :destroy]

  # GET /categories
  def index
    @categories = Category.all
  end

  # GET /categories/1
  def show
  end

  # GET /categories/new
  def new
    @category = Category.new
  end

  # GET /categories/1/edit
  def edit
  end

  # POST /categories
  def create
    @category = Category.new(category_params)

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

  # PATCH/PUT /categories/1
  def update
    respond_to do |format|
      if @category.update(category_params)
        format.html { redirect_to @category, notice: 'Category was successfully updated.' }
        format.json { render :show, status: :ok, location: @category }
      else
        format.html { render :edit }
        format.json { render json: @category.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /categories/1
  def destroy
    @category.destroy
    respond_to do |format|
      format.html { redirect_to categories_url, notice: 'Category was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_category
      @category = Category.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def category_params
      params.require(:category).permit(:name, :desc)
    end
end

Rails routes

             products GET    /products(.:format)                                  products#index
                      POST   /products(.:format)                                  products#create
          new_product GET    /products/new(.:format)                              products#new
         edit_product GET    /products/:id/edit(.:format)                         products#edit
              product GET    /products/:id(.:format)                              products#show
                      PATCH  /products/:id(.:format)                              products#update
                      PUT    /products/:id(.:format)                              products#update
                      DELETE /products/:id(.:format)                              products#destroy
    category_products GET    /categories/:category_id/products(.:format)          products#index
                      POST   /categories/:category_id/products(.:format)          products#create
 new_category_product GET    /categories/:category_id/products/new(.:format)      products#new
edit_category_product GET    /categories/:category_id/products/:id/edit(.:format) products#edit
     category_product GET    /categories/:category_id/products/:id(.:format)      products#show
                      PATCH  /categories/:category_id/products/:id(.:format)      products#update
                      PUT    /categories/:category_id/products/:id(.:format)      products#update
                      DELETE /categories/:category_id/products/:id(.:format)      products#destroy
           categories GET    /categories(.:format)                                categories#index
                      POST   /categories(.:format)                                categories#create
         new_category GET    /categories/new(.:format)                            categories#new
        edit_category GET    /categories/:id/edit(.:format)                       categories#edit
             category GET    /categories/:id(.:format)                            categories#show
                      PATCH  /categories/:id(.:format)                            categories#update
                      PUT    /categories/:id(.:format)                            categories#update
                      DELETE /categories/:id(.:format)                            categories#destroy

Solved

I'm not sure what was wrong, but deleted my codes which are below and rewrote it and now I don't get NoMethodError.

_product.html.erb (index.html.erb)

<% cache product do %>
<div class="col-lg-3 col-sm-4 col-md-4 col-xs-12 products">

  <div class="product-block">
    <div class="product-img-list">
      <h3 id="product-name"><%= product.name %></h3>
      <%= link_to product_path(product), class: 'product_link' do %>
      <span class="product-img-text"><span><h4><i class="glyphicon glyphicon-usd"></i><%= product.price %></h4></span></span>
      <%= image_tag(product.image_url, class: "img-responsive") %>
      <% end %>
    </div>
    <p id="product-description"><%= truncate product.description, length: 100 %></p>
    <%= link_to Category.find(product.category_id).name, category_path(product.category_id) %>
  </div>

  <% if signed_in? && current_user.admin? %>
    <ul>
      <li><%= link_to 'Show', product %></li>
      <li><%= link_to 'Edit', edit_product_path(product) %></li>
      <li><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></li>
    </ul>
  <% end %>

</div><!-- /col -->
<% end %>

Solution

  • If the error says

    undefined method `category' for # Product

    it is because you did not define the association properly. Please include

    belongs_to :category
    

    line in product.rb model.

    If the error description says

    undefined method `name' for nil:NilClass

    then you need to check whether there are any products with category is nil.