Search code examples
ruby-on-railsauthenticationdeviseruby-on-rails-4

before_filter :authenticate_user!, except: [:index] / Rails 4


I Have a Listings Controller (Devise User System) and in Rails 3 i just used

before_filter :authenticate_user!, except: [:index]

to check if a user was signed in before viewing a specific listing.

My Homepage (Index) shows at the bottom a view Listings, the User is able to see them, but as soon as he clicks on one to view it he is redirected to the Login Page.

That's why in my controller i had instead of

Listing.new -> current_user.listings.new

In Rails 4 things seems to have changed and i cant find the right way to do it.

I searched a little bit and found that the command was changed to

before_action :authenticate_user!, :except => [:index]

A Guest can view now the Index but if he clicks on a Listing, he is not redirected to the login page, instead i get this error.

NoMethodError in ListingsController#show
undefined method `listings' for nil:NilClass

# Use callbacks to share common setup or constraints between actions.
def set_listing
        @listing = current_user.listings.find(params[:id])
end

# Never trust parameters from the scary internet, only allow the white list through.

My Listings Controller

class ListingsController < ApplicationController
  before_action :set_listing, only: [:show, :edit, :update, :destroy]
    before_action :authenticate_user!, :except => [:index]

  # GET /listings
  # GET /listings.json
  def index
    @listings = Listing.order("created_at desc")
  end

  # GET /listings/1
  # GET /listings/1.json
  def show
  end

  # GET /listings/new
  def new
        @listing = current_user.listings.build
  end

  # GET /listings/1/edit
  def edit
  end

  # POST /listings
  # POST /listings.json
  def create
        @listing = current_user.listings.build(listing_params)

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

  # PATCH/PUT /listings/1
  # PATCH/PUT /listings/1.json
  def update
    respond_to do |format|
      if @listing.update(listing_params)
        format.html { redirect_to @listing, notice: 'Listing was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: 'edit' }
        format.json { render json: @listing.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /listings/1
  # DELETE /listings/1.json
  def destroy
    @listing.destroy
    respond_to do |format|
      format.html { redirect_to listings_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_listing
            @listing = current_user.listings.find(params[:id])
    end

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

EDIT: PROBLEM 2

If another Logged in User tries to view a listing which another User created im getting this ->

enter image description here

and the log

enter image description here


Solution

  • Try this, this will allow guests to see listing supplied in the parameter:

    def set_listing
        unless current_user
            @listing = Listing.find(params[:id])
        else
            @listing = current_user.listings.find(params[:id])
        end
    end
    

    Update:

    It appears that you want to display listings by parameter and not by the current_user. If so then please update your set_listing definition as follows:

    def set_listing
        @listing = Listing.find(params[:id]) if params[:id]
    end