Search code examples
ruby-on-railscontrollerscaffolding

Why do I have to include @link = Link.find(params[:id]) in my Show action?


I am working on a mock-up of reddit where I submit url & title in a form and then the database should get populated and we should be taken to a show page to see our link and title that we submitted.

My questions is why I have to include this in my controller.

  def show  
    @link = Link.find(params[:id])
  end

If I delete the @link = Link.find(params[:id]) my show doesnt work.

I get the following error:

NoMethodError in Links#show

On this line

<%= @link.title %>

In addition to this I already have this private method:

private
  def set_link
    @link = Link.find(params[:id])
  end
  def link_params
    params.require(:link).permit(:title, :url)
  end

I was comparing to another project where I generated a scaffold for something similar and I only had the private method and no need for @link = Link.find(params[:id]) in my show action.

Here is my full controller code:

class LinksController < ApplicationController

  def index
    @link = Link.all
  end

  def new
    @link = Link.new
  end

  def create
    @link = Link.new(link_params)

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

  def show  
    @link = Link.find(params[:id])
  end


private
  def set_link
    @link = Link.find(params[:id])
  end
  def link_params
    params.require(:link).permit(:title, :url)
  end


end

And here is my full controller for the generated scaffold:

class HighScoresController < ApplicationController
  before_action :set_high_score, only: [:show, :edit, :update, :destroy]

  # GET /high_scores
  # GET /high_scores.json
  def index
    @high_scores = HighScore.all
  end

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

  # GET /high_scores/new
  def new
    @high_score = HighScore.new
  end

  # GET /high_scores/1/edit
  def edit
  end

  # POST /high_scores
  # POST /high_scores.json
  def create
    @high_score = HighScore.new(high_score_params)

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

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

  # DELETE /high_scores/1
  # DELETE /high_scores/1.json
  def destroy
    @high_score.destroy
    respond_to do |format|
      format.html { redirect_to high_scores_url }
      format.json { head :no_content }
    end
  end

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

    # Never trust parameters from the scary internet, only allow the white list through.
    def high_score_params
      params.require(:high_score).permit(:game, :score)
    end
end

Why does the generated scaffold work without the @link = Link.find(params[:id]) in my show action while my own project won't?


Solution

  • You're missing the first line within the controller class of the generated scaffold:

    class HighScoresController < ApplicationController
      before_action :set_high_score, only: [:show, :edit, :update, :destroy]
    

    You need to add a before_action to your controller in order to make your set_link function run:

    class LinksController < ApplicationController
      before_action :set_link, only: [:show]
    

    Before the show action, call the set_link function.