HealthCare Portal Sinatra App

David Ryan Morphew
3 min readDec 22, 2020

Model-Side Issues in Validation & Future Functionality of the HealthCare Portal App

While making my HealthCare Portal App, built with Sinatra (short video on how it works can be found here), I found an interesting issue when I tried to render an .erb page after a failed validation.

The Problem:

  • My patient’s edit page patients/edit.erbis built to show the patient’s current information when you open the edit form. (The <input>field is set to show the current values saved in the database for the patient’s attributes before they’ve been edited and updated).
  • In my app, the “name” and “birthdate” attributes of each patient must be valid per the ActiveRecord validation macros I used :
class Patient < ActiveRecord::Base
validates :name, presence: true
validates :birthdate, presence: true
...
end
  • Using the “patch” HTTP method in my PatientsController(which requires you to mount Rack::MethodOverride in your config.ru), you might expect that if errors are raised when you try to update with invalid fields (i.e. when they’re blank), you could simply print out the validation errors and render the patients/edit.erb file with the errors:
class PatientsController < ApplicationController
...
patch "/patients/:id" do
@patient = Patient.find_by(id: params[:id])
if @patient.update(params[:patient]) # << VALIDATION HERE
redirect "/patients/#{patient.id}"
else
@errors = @patient.errors.full_messages
erb :"patients/edit" # EDIT PAGE RERENDER
end
end
...
end
  • Then you’d expect the errors to be listed when you render the .erb file. What you might not expect, is that the .erb file would render patient attributes you just changed, which now has bad data, rather than the data drawn from the database.
  • In other words, the patient’s name should be what we have in the database, not the bad updated, invalid data, right? (The patient hasn’t been updated to the database, since it failed to save because it was invalid!)
<h1><%= @patient.name %></h1>
<% if @errors %>
<%= @errors.each do |message| %>
<h5><%= message %></h5>
<% end %>
<% end %>
<form method="POST" action="/patients/<%= @patient.id %>">
<input type="hidden" id="hidden" name="_method" value="PATCH">
<h5>Name: </h5>
<input type="text" name="patient[name]" value="<%= @patient.name%>">
...
  • But the data will be bad in yourpatients/edit.erb file. Your edit page is rendering “@patient” with the changed “name” and “birthdate” attributes even though they’re not allowed to save to the database. So, why is the edit page showing the data that was invalid and couldn’t be updated?
  • The problem is model-side, since the instance variable (“@patient”) has been modified and the instance variable is being used in the .erb file (not the data from the database).

The fix:

  • There are two quick fixes for this:
  1. After the validation check, reassign the value of “@patient” from the database right before rendering the erb page:
   patch "/patients/:id" do
@patient = Patient.find_by(id: params[:id])
if @patient.update(params[:patient]) # VALIDATION HERE
redirect "/patients/#{patient.id}"
else
@patient = Patient.find_by(id: params[:id]) # REASSIGNED
@errors = @patient.errors.full_messages
erb :"patients/edit" # RENDER @patient FROM DATABASE
end
end

2. Use your own validation and error message and only update if the fields are valid:

   patch "/patients/:id" do
@patient = Patient.find_by(id: params[:id])
if params[:patient][:name].blank? # CUSTOM VALIDATION HERE
@error = "Error: Name is a required fields"
erb :"patients/edit"
else
@patient = Patient.update(params[:patient]) # UPDATE
redirect "/patients/#{patient.id}"
end
end

Bada-bing, bada-boom! Either way works. You either get the info from the database again, or wait to modify the instance variable until after you’ve checked the data.

So, there you go. If you want to show errors for bad data when updating, make sure that the info you want to display from the database doesn’t get over-written model-side!

Future Functionality of My App

I included in my program a draw.io set of tables for future expansion of the app.

  • Right now, “medications” are simply a string attribute of patients , but it would make sense to make a separate medications table and Medication model, and then set up a has_many- has_many relationship through a join table between patients and medications.
  • The join table would be called prescriptions and have further attributes like “dosage” and “frequency.” As a join table, it also would have foreign keys for both of the tables it joins, namely the medications and patients tables.
class CreatePrescriptions < ActiveRecord::Migration
def change
create_table :prescriptions do |t|
t.string :dosage
t.string :frequency
t.integer :patient_id
t.integer :medication_id
end
end
end

On the model side, the has_many-has_many relationship needs to be set up like so:

class Patient < ActiveRecord::Base
has_many :prescriptions
has_many :medications, through: :prescriptions
...
end

and:

class Medication < ActiveRecord::Base
has_many :prescriptions
has_many :patients, through: :prescriptions
...
end

and also:

class Prescription < ActiveRecord::Base
belongs_to :patient
belongs_to :medication
end

With this in place, a healthcare worker will be able to assign medications to patients through prescriptions, and those medications will be administered at dosages and frequencies tailored to each patient.

--

--

David Ryan Morphew

I’m very excited to start a new career in Software Engineering. I love the languages, frameworks, and libraries I’ve already learned / worked with (Ruby, Rails,