Question

Hi I'm a newbie programmer and probably my question is stupid but I was searching through the net (and on this site) and I couldn't find the answer (probably I didn't ask properly).

The thing is I have 3 kinds of users in my app: patients, doctors and administrators and I want that each of them (once loged in) can see just some of the pages. For example, doctors must only have access to its profile and some patients data page, patients must only have access to the page with his data, and administrators must only have access to the admin page.

How can I filter the access to the pages depending of the type of user?

Thank you very much in advance.

Was it helpful?

Solution

When you have your user authenticated with e.g. Devise or Clearance, the signed in user is available through the current_user method. Just scope all your calls to the current user.

class PatientsController < ApplicationController
  def index
    @patients = current_user.patients
  end

  def show
    # Will raise an ActiveRecord::RecordNotFound exception
    # if there is not patient with given id or the patient 
    # is not associated with the current_user
    # Renders a 404 error in production
    @patient = current_user.patients.find(params[:id])
  end
end

An example from Rails Best Practices:

class PostsController < ApplicationController
  def edit
    # raise RecordNotFound exception (404 error) if not found
    @post = current_user.posts.find(params[:id])
  end
end

So we find the post only in current_user.posts that can promise the post is owned by current_user, if not, a 404 error will be raised. We have no needs to compare the owner with current_user, just use scope access to make permission check simpler.

An example

class User < AR::B
  has_many :patients
  has_many :reports, through: :patients
end

class Patient < AR::B
  belongs_to :user
  has_many :reports
end

class Report < AR::B
  belongs_to :patient
end

# config/routes.rb
resources :patients

class PatientsController < ApplicationController
  # Ensure that a user is signed in (via Devise)
  before_action :authenticate_user! # before_filter in Rails 3

  # Load the patient before certain actions
  before_action :load_patient, only: [:show, :edit, :update, :destroy]

  def index
    # Scoping to the current_user ensures that a doctor can only see his patients 
    @patients = current_user.patients
  end

  def show
  end

  def new
    @patient = current_user.patients.build
  end

  def create
    @patient = current_user.patients.build(patient_params)
    if @patient.save
      redirect_to @patient, notice: 'Patient has been created.'
    else
      render :new
    end
  end

  def edit
  end

  def update
    if @patient.save
      redirect_to @patient, notice: 'Patient has been updated.'
    else
      render :edit
    end
  end

  def destroy
    @patient.destroy
    redirect_to patients_path, notice: 'Patient has been destroyed.'
  end

  private

  def load_patient
    @patient = current_user.patients.find(params[:id])
  end

  def patient_params
    params.require(:patient).permit(:first_name, :last_name)
  end
end

Scoping gives users the ability to only edit their own records and the ones they are associated with.

When you need finer-grained access logic (e.g. a patient can send a message to the doctor only if the doctor wants to receive messages), I'd suggest you look into Pundit.

Hope this helps!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top