Home > OS >  Rails => routing index to two different pages depending on the current_user
Rails => routing index to two different pages depending on the current_user

Time:03-02

I'm using Rails and I have two views in bookings (clients and trainers). I'm trying to route from index to client or trainers depending on who is the current_user.

If I'm a client, route index to trainers If I'm a trainer, route index to clients

class BookingsController < ApplicationController
  def index

  end

  def clients
    @bookings = Booking.where(client: current_user)
    @clients = current_user.bookings.map(&:client)
  end

  def trainers
    @trainers = current_user.bookings.map(&:user)
  end

end
Rails.application.routes.draw do
  resources :bookings do
    collection do
      get "/clients", to: "bookings#clients", as: "clients"
      get "/trainers", to: "bookings#trainers", as: "trainers"
    end
    resources :shared_training_plans, except: [:new]
  end
end

CodePudding user response:

You're doing nesting backwards. And the output of your routes should actually look more like:

GET /instructors/1/bookings # bookings belonging to instructor 1
GET /instructors/1/clients  # clients that are associated with instructor 1
GET /students/3/bookings    # bookings belonging to student 3
GET /students/3/instructors # instructors belonging to student 3

This describes RESTfully that the endpoint returns something belonging to the other resource. This should be handled by the index action - ideally of a controller designated for that purpose as each controller should only be responsible for one resource.

You could define these routes as:

resources :instructors do
  resources :bookings, module: :instructors
end

resources :clients do
  resources :bookings, module: :clients
end
module Instructors
  class ClientsController < ApplicationController
    # GET /instructors/1/clients
    def index 
      @instructor = Instructor.find(params[:instructor_id])
      @clients = @instructor.clients
    end
  end
end
module Clients
  class InstructorsController < ApplicationController
    # GET /clients/1/clients
    def index 
      @client = Client.find(params[:client_id])
      @clients = @client.instrucors
    end
  end
end

You can implement this by reimagining the feature so that you link the "specific users URL" instead of a generic URL. You can see this for example on the dashboard here on Stackoverflow which uses https://stackoverflow.com/users/{id}/{username}.

REST is in theory supposed to be stateless so each path should return the same resource no matter who is requesting it. But like all rules this could be broken and you can set up routes like:

GET /user/bookings # GET bookings for the currently signed in user

Which would return different results for the signed in user which is stateful. user here would be consider a singular resource. This is mostly useful if you need to have a significantly different represention of the resource when viewing "your own" vs "others".

To actually be able to use the "current user" from the routes the authentication system must be implemented as Rack middleware (like Devise is) and not on the controller level as almost all the "reinventing the wheel" tutorials are. Routing is Rails is implemented as Rack middeware that is run before your controller is ever instanciated.

Devise has the authenticated routing helper which lets you setup different routes for authenticated/unauthenticated users. For example if instructors are implemented as different warden scopes:

authenticated :instructor do
  resource :bookings, controller: 'instructors/bookings', only: [:index]
end

authenticated :student do
  resource :bookings, controller: 'students/bookings', only: [:index]
end

But you could also use a lambda if you only have one warden scope (the typical Devise configuration):

authenticate :user, ->{|u| u.instructor? } do
  resource :bookings, controller: 'instructors/bookings', only: [:index]
end

authenticate :user, ->{|u| u.student? } do
  resource :bookings, controller: 'students/bookings', only: [:index]
end

Both of these would route GET /bookings to Instructors::BookingsController#index and Students::BookingsController#indexdepending on which "role" the user has.

  • Related