Commit 3c898ef6 authored by Greg Gard's avatar Greg Gard

adding flash/page notifications, tweaking strong params, enabling resource,...

adding flash/page notifications, tweaking strong params, enabling resource, resource_params in controller/view
parent 2c3aedc6
......@@ -3,6 +3,9 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '2.5.1'
# ***********************
# stock rails 5.2 gems
#
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.2.0'
# Use sqlite3 as the database for Active Record
......@@ -36,12 +39,20 @@ gem 'jbuilder', '~> 2.5'
# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.1.0', require: false
# ********************************
# emt gems
#
# bootstrap 3 sass
# https://github.com/twbs/bootstrap-sass
gem 'jquery-rails'
# gem 'sass-rails', '>= 3.2' # already included above
gem 'bootstrap-sass', '~> 3.3.7'
gem 'kaminari' # pagination - could use will_paginate instead, but this is more modern/cleaner
# **********************
# per env
#
group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
......
......@@ -93,6 +93,18 @@ GEM
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
kaminari (1.1.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.1.1)
kaminari-activerecord (= 1.1.1)
kaminari-core (= 1.1.1)
kaminari-actionview (1.1.1)
actionview
kaminari-core (= 1.1.1)
kaminari-activerecord (1.1.1)
activerecord
kaminari-core (= 1.1.1)
kaminari-core (1.1.1)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
......@@ -209,6 +221,7 @@ DEPENDENCIES
coffee-rails (~> 4.2)
jbuilder (~> 2.5)
jquery-rails
kaminari
listen (>= 3.0.5, < 3.2)
puma (~> 3.11)
rails (~> 5.2.0)
......
......@@ -18,26 +18,48 @@ main { @extend .container };
@extend .row;
> div { @extend .col-md-4 };
}
&-btn {
@extend .btn;
}
// use with btn force override eg form
&-brand {
background-color: $brand !important;
color: $white !important;
background-color: $brand;
a {
color: $white;
font-size: 1.5rem;
&:hover{
}
}
}
&-card {
@extend .panel, .panel-default;
div:nth-of-type(1) {
@extend .panel-heading;
background-color: $brand;
a {
color: $white;
font-size: 1.5rem;
&:hover{
}
}
@extend .emt-brand;
}
div:nth-of-type(2) { @extend .panel-body }
div:nth-of-type(3) {
@extend .panel-footer;
}
}
} // card
&-table {
@extend .table, .table-striped;
}
&-form {
> div {
@extend .form-group;
> input, > textarea, > select, > checkbox { @extend .form-control; }
}
}
}
\ No newline at end of file
.transfers{
&-dashboard {
h3 {border-bottom: solid 1px #AAA;}
}
.emt{
.transfers{
&-dashboard {
h3 {border-bottom: solid 1px #AAA;}
}
} // transfers
}
\ No newline at end of file
class AdmissionsController < ApplicationController
def index
end
def new
end
def create
end
def show
end
def edit
end
def update
end
def destroy
end
end
\ No newline at end of file
class AllergiesController < ApplicationController
def index
end
def new
end
def create
end
def show
end
def edit
end
def update
end
def destroy
end
end
\ No newline at end of file
class ApplicationController < ActionController::Base
before_action :set_presenter
before_action :set_resource, only: [:show, :edit, :update, :destroy]
# override in subclasses to load a different presenter by default
def self.default_presenter
Object.const_get(name.demodulize.sub(/Controller$/, 'Presenter')) # rescue ApplicationPresenter
Object.const_get(name.demodulize.sub(/Controller$/, 'Presenter')) rescue ApplicationPresenter
end
@@resource_classes = {}
def self.set_resource_class(klass)
@@resource_classes[name] = klass
end
# gets set when set_resource is called unless overriden with set_resource_class
# - could use inherited hook to trigger call if we needed earlier
# - not using sti here but prevent sti kids from having own resource params
def self.resource_class
@@resource_classes[name] ||= Object.get_const(controller_name.singularize).base_class
end
# *******************************
# instance methods
#
attr_accessor :presenter
attr_accessor :presenter, :resource, :resource_params
# all controllers get a presenter even if just base class
def set_presenter(klass = self.class.default_presenter)
......@@ -22,5 +35,27 @@ class ApplicationController < ActionController::Base
)
end
def set_resource(klass = self.class.resource_class)
self.resource = klass.find(params[:id])
instance_variable_set :"@#{klass.name.underscore}", resource
resource
end
def set_resource_params(_resource = resource)
return unless _resource
params.require(resource.class.name.underscore.to_sym).permit(resource.class.params_whitelist)
end
# override in kids or set model whitelist
def resource_params
@resource_params ||= set_resource_params
end
end
# sugar so we don't have to deal with @ivars all the time. rails imports ivars
# from controller into view class so these get set through that mechanism.
class ActionView::Base
attr_accessor :presenter, :resource, :resource_params
end
\ No newline at end of file
class DiagnosesController < ApplicationController
def index
end
def new
end
def create
end
def show
end
def edit
end
def update
end
def destroy
end
end
\ No newline at end of file
class DiagnosticProceduresController < ApplicationController
def index
end
def new
end
def create
end
def show
end
def edit
end
def update
end
def destroy
end
end
\ No newline at end of file
class FacilitiesController < ApplicationController
def index
end
def new
end
def create
end
def show
end
def edit
end
def update
end
def destroy
end
end
\ No newline at end of file
class MedicationOrdersController < ApplicationController
def index
end
def new
end
def create
end
def show
end
def edit
end
def update
end
def destroy
end
end
\ No newline at end of file
class ObservationsController < ApplicationController
def index
end
def new
end
def create
end
def show
end
def edit
end
def update
end
def destroy
end
end
\ No newline at end of file
class PatientsController < ApplicationController
set_resource_class Patient
def index
@patients = Patient.order(:last_name, :first_name, :middle_name).page params[:page]
end
def new
@patient = Patient.new
end
def create
@patient = Patient.new(params[:patient])
end
def show
end
def edit
end
def update
@patient.update_attributes! resource_params
redirect_to patients_path, notice: "Patient updated"
rescue => e
logger.error e
flash.now[:error] = "Unable to save"
render :edit
end
def destroy
end
# ************************
private
end
\ No newline at end of file
class SymptomsController < ApplicationController
def index
end
def new
end
def create
end
def show
end
def edit
end
def update
end
def destroy
end
end
\ No newline at end of file
......@@ -7,8 +7,8 @@
#
class TransfersController < ApplicationController
# main application landing page
def dashboard
end
def index
......@@ -31,16 +31,12 @@ class TransfersController < ApplicationController
render html: presenter.edit_transfer
end
def patch
render html: presenter.update_transfer
end
def update
render html: presenter.update_transfer
end
def destroy
render html: presenter.delete_ransfer
render html: presenter.delete_transfer
end
......
class PatientsController < ApplicationController
def index
end
def new
end
def create
end
def show
end
def edit
end
def update
end
def destroy
end
end
\ No newline at end of file
module ApplicationHelper
attr_accessor :skip_navbar, :skip_page_title, :skip_page_notifications
def emt_navbar
return if skip_navbar
%Q[<div class='emt-navbar'>
<div>
#{link_to EMT::APP_NAME, root_path, class: 'brand'}
......@@ -10,4 +11,42 @@ module ApplicationHelper
</div>].html_safe
end
def emt_default_page_title
controller ? "#{controller_name.titleize}: #{action_name.to_s.titleize}" : EMT::APP_NAME
end
def emt_page_title(title = nil)
return if skip_page_title
title = title.presence || emt_default_page_title
tag.h4 title, class: 'emt-page-title'
end
# dump flash/flash.now to message list
# TODO: push notifications via ActionCable - toaster intetgrated with navbar?
# TODO: colorize based on priority/severity with related icons
def emt_page_notifications
return if skip_page_notifications
# dump and clear
messages = flash.to_hash.values.reject(&:blank?)
flash.clear
return if messages.empty?
%Q[<div class='emt-page-notifications'>
<h5>Notice:</h5>
<ul>#{messages.map{|m| tag.li m}.join}</ul>
</div>].html_safe
end
# expects model from controller
def emt_form_errors(resource)
return unless resource && resource.errors.present?
%Q[<div id="emt-form-errors">
<h5>#{pluralize(resource.errors.count, "error")} errors:</h5>
<ul>#{resource.errors.full_messages.map{|msg| tag.li msg}}</ul>
</div>].html_safe
end
end
#
# general "app" library code that doesn't need to be loaded early for config/boot/init
# - grep config for more refs for early loaded code
#
module EMT
APP_NAME = "Emergency Transfers"
end
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
# override in kids else u won't be able to save anything viz strong params
# this is not an effort to undo strong params, just relocate the logic
# back to the model.
def self.params_whitelist
[]
end
end
......@@ -2,9 +2,43 @@ class Patient < ApplicationRecord
enum gender: {male: 1, female: 2, other: 0}
# TODO: make mr auto-assigned? if so then disallow mass assign, admins only on renaming?
def self.params_whitelist
[:mr, :first_name, :middle_name, :last_name, :dob, :sex]
end
# ***************************
# instance methods
#
has_many :admissions
has_many :allergies
has_many :medication_orders
has_many :diagnostic_procedures
has_many :treatments
alias_attribute :sex, :gender # TODO: make distinction in db eg biological state vs identity
# *********************************
# utils/formatting
# - common methods to app. if this is api-specific or
# really one-off/complicated, write a decorator/driver class
#
def name(format = :lfm)
case format.to_s.downcase
when 'fmml'
[first_name, middle_name, last_name]
when 'f'
[first_name]
else
[last_name, first_name, middle_initial]
end.reject(&:blank?).join(', ')
end
def middle_initial
middle_name.presence ? middle_name[0] : nil
end
def fmt_dob
dob&.to_formatted_s(:dob)
end
end
\ No newline at end of file
......@@ -12,6 +12,8 @@
<body>
<main>
<%= emt_navbar %>
<%= emt_page_notifications %>
<%= emt_page_title %>
<%= yield %>
</main>
</body>
......
<%= form_with model: patient, class: 'emt-patients-form emt-form' do |f| %>
<%= emt_form_errors(patient) %>
<div>
<%= f.label :mr, "Medical Record Number" %>
<%= f.text_field :mr %>
</div>
<div>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
</div>
<div>
<%= f.label :middle_name %>
<%= f.text_field :middle_name %>
</div>
<div>
<%= f.label :last_name %>
<%= f.text_field :last_name %>
</div>
<div>
<%= f.label :dob_name %>
<%= f.text_field :first_name %>
</div>
<div>
<%= f.label :sex %>
<%= f.text_field :sex %>
</div>
<div>
<%= f.submit "Save", class: 'emt-btn emt-brand' %>
</div>
<% end %>
\ No newline at end of file
<div class='emt-patients-edit'>