Search code examples
ruby-on-railsrubyruby-on-rails-4link-tonested-routes

Rails 4 Nested Routing Back to Parent's Show Page


In my web app I created two Modules; Clients and Workers. My issue is that I can't create a 'Back' link from workers#index to clients#show. In other words, I want to create this in the URL:

http://localhost:3000/clients/1

I believe it has to do with not entering the right URL helper. When I run rake routes I see the path I want, this leads me to believe I've nested the resources correctly. However I keep can't seem to enter the right parameter to go back to the client#show page instead of clients#index.

Prefix Verb   URI Pattern                                    Controller#Action
    client_workers GET    /clients/:client_id/workers(.:format)          workers#index
                   POST   /clients/:client_id/workers(.:format)          workers#create
 new_client_worker GET    /clients/:client_id/workers/new(.:format)      workers#new
edit_client_worker GET    /clients/:client_id/workers/:id/edit(.:format) workers#edit
     client_worker GET    /clients/:client_id/workers/:id(.:format)      workers#show
                   PATCH  /clients/:client_id/workers/:id(.:format)      workers#update
                   PUT    /clients/:client_id/workers/:id(.:format)      workers#update
                   DELETE /clients/:client_id/workers/:id(.:format)      workers#destroy
           clients GET    /clients(.:format)                             clients#index
                   POST   /clients(.:format)                             clients#create
        new_client GET    /clients/new(.:format)                         clients#new
       edit_client GET    /clients/:id/edit(.:format)                    clients#edit
            client GET    /clients/:id(.:format)                         clients#show
                   PATCH  /clients/:id(.:format)                         clients#update
                   PUT    /clients/:id(.:format)                         clients#update
                   DELETE /clients/:id(.:format)                         clients#destroy
              root GET    /                                              clients#index

In app/views/workers/show.html.erb I have the link of: <%= link_to 'Back', client_path(@client) %>.

Worker's Controller

class WorkersController < ApplicationController
  before_action :set_worker, only: [:show, :edit, :update, :destroy]

  # GET /clients/:client_id/workers
  # GET /clients/:post_id/workers.xml
  def index
    #1st you retrieve the client thanks to params[:client_id]
    client = Client.find(params[:client_id])
    #2nd you get all the workers of this client
    @workers = client.workers

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @comments }
    end
  end

  # GET /clients/:client_id/workers/:id
  # GET /workers/:id.xml
  def show
    #1st you retrieve the client thanks to params[:client_id]
    @client = Client.find(params[:client_id])
    #2nd you retrieve the comment thanks to params[:id]
    @worker = client.workers.find(params[:id])

    respond_to do |format|
      format.html # show.html.erb
      format.xml  { render :xml => @comment }
    end
  end

  # GET /clients/:client_id/workers/new
  # GET /clients/:client_id/workers/new.xml
  def new
    #1st you retrieve the post thanks to params[:post_id]
    client = Client.find(params[:client_id])
    #2nd you build a new one
    @worker = client.workers.build

    respond_to do |format|
      format.html # new.html.erb
      format.xml  { render :xml => @comment }
    end
  end

  # GET /posts/:post_id/comments/:id/edit
  # GET /clients/:client_id/workers/:id/edit
  def edit
    #1st you retrieve the post thanks to params[:post_id])
    client = Client.find(params[:client_id])
    #2nd you retrieve the comment thanks to params[:id]
    @worker = client.workers.find(params[:id])
  end

  # POST /client/:client_id/workers
  # POST /client/:client_id/worker.xml
  def create
    #1st you retrieve the post thanks to params[:post_id]
    client = Client.find(params[:client_id])
    #2nd you create the comment with arguments in params[:comment]
    @worker = client.workers.create(worker_params)

    respond_to do |format|
      if @worker.save
        #1st argument of redirect_to is an array, in order to build the correct route to the nested resource comment
        format.html { redirect_to([@worker.client, @worker], :notice => 'Worker was successfully created.') }
        #the key :location is associated to an array in order to build the correct route to the nested resource comment
        format.xml  { render :xml => @worker, :status => :created, :location => [@worker.client, @worker] }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @worker.errors, :status => :unprocessable_entity }
      end
    end
  end

  # PUT /client/:client_id/Workers/:id
  # PUT /client/:client_id/workers/:id.xml
  def update
    #1st you retrieve the post thanks to params[:post_id]
    client = Client.find(params[:client_id])
    #2nd you retrieve the comment thanks to params[:id]
    @worker = client.workers.find(params[:id])

    respond_to do |format|
      if @worker.update_attributes(worker_params)
        #1st argument of redirect_to is an array, in order to build the correct route to the nested resource comment
        format.html { redirect_to([@worker.client, @worker], :notice => 'Worker was successfully updated.') }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @worker.errors, :status => :unprocessable_entity }
      end
    end
  end

  # DELETE /client/:client_id/workers/1
  # DELETE /client/:client_id/worker/1.xml
  def destroy
    #1st you retrieve the post thanks to params[:post_id]
    client = Client.find(params[:client_id])
    #2nd you retrieve the comment thanks to params[:id]
    @worker = client.workers.find(params[:id])
    @worker.destroy

    respond_to do |format|
      #1st argument reference the path /posts/:post_id/comments/
      format.html { redirect_to(client_workers_url) }
      format.xml  { head :ok }
    end
  end

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

    # Never trust parameters from the scary internet, only allow the white list through.
    def worker_params
      params.require(:worker).permit(:first_name, :last_name, :birth_day, :birth_month, :birth_year, :birth_city, :birth_state, :client_id)
    end
end

Solution

  • Thanks to everyone in the comments we were able to find the answer. I decided to group the answers together so it would be easier for others who have this issue to find this post.

    The correct link is: <%= link_to 'Back', client_path(@client) %>

    For this to work I had to change the WorkersController #show and #index Method to the following:

    class WorkersController < ApplicationController
    def index
      #1st you retrieve the client thanks to params[:client_id]
      @client = Client.find(params[:client_id])
      #2nd you get all the workers of this client
      @workers = @client.workers
    
      respond_to do |format|
        format.html # index.html.erb
        format.xml  { render :xml => @comments }
      end
    end
    
    # GET /clients/:client_id/workers/:id
    # GET /workers/:id.xml
    def show
      #1st you retrieve the client thanks to params[:client_id]
      @client = Client.find(params[:client_id])
      #2nd you retrieve the comment thanks to params[:id]
      @worker = client.workers.find(params[:id])
    
      respond_to do |format|
        format.html # show.html.erb
        format.xml  { render :xml => @comment }
      end
    end
    

    Essentially, changing the local variable client into an instance variable @client so it's accessible.