0

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
hp001
  • 79
  • 10
  • Can you post your `workers_controller`? – Pavan Jul 11 '16 at 18:33
  • If you want to link from `/clients/1/workers` back to `/clients/1`, you're using the wrong path. You should be using `client_path(some_client)`. – user229044 Jul 11 '16 at 18:34
  • Meaga, how do I indicate 'some_client'? With an instance variable or an id attribute? – hp001 Jul 11 '16 at 18:37
  • 1
    Just change `client` to `@client` in `show` method and use `client_path(@client)` – Pavan Jul 11 '16 at 18:45
  • Pavan, I updated the corrections to the body of the code posted above. When I clicked on the link I got an error of: `No route matches {:action=>"show", :controller=>"clients", :id=>nil} missing required keys: [:id]` – hp001 Jul 11 '16 at 18:55
  • 1
    did you change the local variable `client` in `WorkersController#index` to `@client` (instance variable) similar to what @Pavan suggested in the `#show` action. The problem is the local variable `client` will not be passed to the view but rather it will be disposed of when you leave the context of the action but the instance variable will be passed to the view and will be accessible for the routing you need. – engineersmnky Jul 11 '16 at 19:09
  • Engineersmnky, Thank you! That was the answer. – hp001 Jul 11 '16 at 19:13

2 Answers2

1

The url that you want requires a :id after /clients/. Your routes says that the /clients/:id has the path as client_path instead of clients_path. (client GET /clients/:id(.:format)clients#show ). So, if you have that id in that workers#index page, you can write it as

<%= link_to 'Back', client_path(@client) %>. Crosscheck the syntax and try.

CfourPiO
  • 351
  • 1
  • 16
1

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.

hp001
  • 79
  • 10