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!