user3765405
user3765405

Reputation: 13

NoMethodError for Devise current_user when calling associated has_many model

I'm following along with One Month Rails and I got stuck at the Pins Users and Associations video. I just can't figure out what's wrong with my code, any help would be appreciated.

When I try to access a pin that I'm not the user of, instead of an alert and redirect coming up I get:

NoMethodError in PinsController#edit

undefined method `pins' for nil:NilClass

Error message says something is wrong in this line:

        def correct_user
          @pin = current_user.pins.find_by(id: params[:id])
          redirect_to pins_path, notice: "Not authorized to edit this pin" if @pin.nil?
        end

I tried restarting the whole thing but I hit the same error.

Here is my pins_controller code:

class PinsController < ApplicationController
  before_action :set_pin, only: [:show, :edit, :update, :destroy]
  before_action :correct_user, only: [:edit, :update, :destroy]
  before_action :authenticate_user!, except: [:index, :show]

  def index
    @pins = Pin.all
  end

   def show
  end

  def new
    @pin = current_user.pins.build
  end

  def edit
  end

  def create
    @pin = current_user.pins.build(pin_params)
    if @pin.save
      redirect_to @pin, notice: 'Pin was successfully created.'
    else
      render action: 'new'
    end
  end

  def update
    if @pin.update(pin_params)
      redirect_to @pin, notice: 'Pin was successfully updated.'
    else
      render action: 'edit'
    end
  end

  def destroy
    @pin.destroy
    redirect_to pins_url
  end

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

    def correct_user
      @pin = current_user.pins.find_by(id: params[:id])
      redirect_to pins_path, notice: "Not authorized to edit this pin" if @pin.nil?
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def pin_params
      params.require(:pin).permit(:description)
    end
end

Here is my user.rb model code:

class User < ActiveRecord::Base
      # Include default devise modules. Others available are:
      # :token_authenticatable, :confirmable,
      # :lockable, :timeoutable and :omniauthable
          devise :database_authenticatable, :registerable,
             :recoverable, :rememberable, :trackable, :validatable

      has_many :pins
    end

Here is my pin.rb model code:

    class Pin < ActiveRecord::Base
        belongs_to :user
    end

And here is the github repo: https://github.com/ModernMeat/pinteresting

Upvotes: 1

Views: 1062

Answers (2)

Rustam Gasanov
Rustam Gasanov

Reputation: 15781

I would suggest you to change order of before_filter's like this

class PinsController < ApplicationController
  before_action :authenticate_user!, except: [:index, :show]
  before_action :set_pin, only: [:show, :edit, :update, :destroy]
  before_action :correct_user, only: [:edit, :update, :destroy]

because you should first authenticate user with devise and only after that check whether it is correct user.

Upvotes: 2

Ven
Ven

Reputation: 19039

Look at the error message a bit more closely : "for nil:NilClass". This tells you that current_user is nil -- which it is indeed, when the user is not logged in.

If you want to make sure the user is logged in to access to the Pins controller, you can use a before_action in your controller :

class PinsController < ApplicationController
  before_action :authenticate_user!

(authenticate_user! being a method declared by devise).

Upvotes: 0

Related Questions