[UNMAINTAINED] This repository is not actively maintained, and issues, pull requests, and security warnings are not regularly reviewed or responded to. Any use of this repository is at your own risk, though you're always welcome to try filing an issue/PR on the off chance someone might see it! :-)
Note: This repo was the basis for a building inspection scheduling and planning tool launched in the City of Long Beach in 2016. While the City maintains (as of 2019-09-14) a similar tool based on this codebase, this codebase is no longer under development, and is entirely separate from the codebase used in production by the city.
- Docker v1.12.1 (or higher)
Configure the web and database containers in docker-compose.yml and run:
$ docker-compose build
This will build all the necessary containers. Please note that you will also need to rebuild the container if you change the Gemfile of Gemfile.lock files.
Next, follow the instructions from the Perparing the Database and Seeding sections.
postgres 9.5
postgis 2.2.x
The City of Long Beach uses a "state plane" coordinate projection system by default for most of its GIS data. This application needs to ingest city-created GIS data, but postgis does not include this particular projection by default. It is readily available for import from spatialreference.org at http://spatialreference.org/ref/esri/102645/.
First, spin up the DB docker image:
$ docker-compose -f docker-compose.yml -f docker-compose.dev.yml up db
Configure the databse settings by modifying config/database.yml
. With the settings in place, create and setup the database:
$ docker-compose -f docker-compose.yml -f docker-compose.dev.yml run web rake db:setup
Next, access the command line of the Inspector Gadget DB docker image:
$ docker exec -it inspectorgadget_db_1 /bin/bash
Switch to the postgres
user:
$ su postgres
Next, run the following query directly against the database via psql
to insert the projection information:
$ psql
$ \connect inspector_gadget_development
INSERT into spatial_ref_sys (srid, auth_name, auth_srid, proj4text, srtext) values ( 102645, 'esri', 102645, '+proj=lcc +lat_1=34.03333333333333 +lat_2=35.46666666666667 +lat_0=33.5 +lon_0=-118 +x_0=2000000 +y_0=500000.0000000002 +ellps=GRS80 +datum=NAD83 +to_meter=0.3048006096012192 +no_defs ', 'PROJCS["NAD_1983_StatePlane_California_V_FIPS_0405_Feet",GEOGCS["GCS_North_American_1983",DATUM["North_American_Datum_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Lambert_Conformal_Conic_2SP"],PARAMETER["False_Easting",6561666.666666666],PARAMETER["False_Northing",1640416.666666667],PARAMETER["Central_Meridian",-118],PARAMETER["Standard_Parallel_1",34.03333333333333],PARAMETER["Standard_Parallel_2",35.46666666666667],PARAMETER["Latitude_Of_Origin",33.5],UNIT["Foot_US",0.30480060960121924],AUTHORITY["EPSG","102645"]]');
Note that the above query has one small change from the query available on spatialreference.org: it removes a preceding "9" from the SRID 9102645
to make it 102645
. It seems as though the 9 was a remnant of darker times. This change was gleaned from this Stack Exchange post.
Repeat the above step for the inspector_gadget_test
database. After running the above DDL INSERT statement, be sure to exit out of the postgres and container shells respectively.
While the db
image is running, populate the database with seeds via rake:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml run web bundle exec rake db:seed:inspectors
docker-compose -f docker-compose.yml -f docker-compose.dev.yml run web bundle exec rake db:seed:inspection_types
docker-compose -f docker-compose.yml -f docker-compose.dev.yml run web bundle exec rake import:inspector_regions
Make sure eveything is working by running our tests:
$ docker-compose -f docker-compose.yml -f docker-compose.dev.yml run web bundle exec rspec
- You can serve the app (in development mode) by running:
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
- You can interact with a rails console by running:
docker-compose run web rails console
- In order to interact with the application in development, you will need to create a test user. For example, you can achieve this by running something like
User.create!({:email => "[email protected]", :password => "hunter2", :password_confirmation => "hunter2" })
on the rails console to create your test user.
When inspections are viewed (e.g. on the /inspections_print
or /reports
pages), the inspector for each inspection is displayed. This relationship is not stored in the database, though, but rather calculated on the fly, and involves enough steps/associations that it bears explaining here.
-
An
Inspection
(seemodels/inspection.rb
) calls itsinspector
method. This method gets a list of all inspectors that serve theInspectionType
for thatInspection
(e.g. all fire inspectors), then finds which of those inspectors is responsible for the GIS area where theInspection
is located. -
To get the list of inspectors for that
InspectionType
, theInspection
delegates delegates to a method on theInspectionType
calledpossible_inspectors
. -
The
possible_inspectors
method uses an association calledinspector_profiles
to find all the inspectors for thatInspectionType
. A couple of things to note about this association:
-
This association exists through the
assignments
table. This table is created by a seed task (db/seeds/inspection_types.rb
) that contains one row for every pairing of anInspectionType
and an inspector. This table is only ever built by a rake task, and only needs to be changed if theInspectionType
assignments change in the app (e.g. if an inspector joins or leaves the City). For more info on building this table, see the "Updating Inspection Type Assignment Rules" section of this README. -
This association is with the
InspectorProfile
model, not theInspector
model. This is because theInspector
model is actually just an extension of theUser
class, and doesn't contain information specific to inspectors - that's stored on theInspectorProfile
model, which eachInspector
modelhas_one
of.
Heroku provides a database import feature. Because importing an entire database is a major operation, and has the potential to overwrite or destroy data, the command line utility has several warnings before it begins work.
First, make sure the web
container is up. You can accomplish this by running:
$ docker-compose -f docker-compose.yml -f docker-compose.dev.yml up web
Next, access the command line of the Inspector Gadget web container:
$ docker exec -it inspectorgadget_web_1 /bin/bash
Next, login to Heroku with your account credentials:
$ heroku
Afterward, create a new backup of the current state of the database:
$ heroku pg:backups capture --app inspector-gadget-cfa
Download the dump to the project directory:
$ curl -o latest.dump `heroku pg:backups public-url --app inspector-gadget-cfa`
Close/terminate the web image bash session after downloading the dump.
Next, access the command line of the Bizport DB docker image:
$ docker exec -it inspectorgadget_db_1 /bin/bash
Then restore from latest.dump with pg_restore
:
$ su postgres
$ pg_restore --verbose --clean --no-acl --no-owner -h localhost -U postgres -d inspector_gadget_development /inspector-gadget/latest.dump
Close/terminate the inspectorgadget_db_1 image bash session. You are now ready to start the web application with a copy of production data.
From time to time, the way that inspections are assigned to inspectors may change. There are two general ways that these assignments will change:
- Changing the underlying GIS data that defines which sections of the city are served by which inspectors; and
- Changing which types of inspections (e.g. plumbing, photovoltaic) are assigned to which inspectors
Because updating this data can have a major impact on the way the application peforms in production, it is recommended to test these changes locally before deploying them. See the section on "Populating a Local Database" in this document to set up an easy environment for trying this.
Inspector GIS data is imported by running a rake task (defined in lib/tasks/import.rake
) at the command line: bundle exec rake import:inspector_regions
. The task assumes that the B_Insp_Com.zip
, B_Insp_Ele.zip
, and B_Insp_Res.zip
source GIS data files are stored in data/gis/
as one or more zip files exported from ArcGIS. These zip files contain (among other things) a shapefile (.shp
) that the RGeo gem can ingest and store in the database. These files are provided by the City of Long Beach GIS team.
Each layer of the shapefile must include an attribute called INSPECTOR
with an inspector's last name. Name comparison is done with SQL ILIKE
, so is not case sensitive.
Running the task will generate a report in the console that indicates which GIS data was assigned to an inspector. Some GIS data will not be assigned to inspectors, as it may reference Signal Hill (SH) or sections within Long Beach that belong to LA County (LAC) and are therefore not managed by Long Beach inspectors.
Inspection assignments are made via the inspector
instance method on the Inspection
model (app/models/inspection.rb
). For speed, this method makes use of a join table (effectively a caching table) called assignments
(model in app/models/assignment.rb
), which makes it fast to look up which types of inspections each inspector handles.
The assignments
table is seeded by running bundle exec rake db:seed:inspection_types
.
Because the table is built based on which inspection types inspectors handle (indicated by the inspection_assignments
attribute on an InspectorProfile
), it is advisable to update the and run the Inspector seeds (db/seeds/inspectors.rb
) before seeding the assignments
table.
So a typical process for updating the assignments would be:
- Update the inspector seeds (
db/seeds/inspectors.rb
) with any assignment or personnel changes. - Update the inspection_type seeds (
db/seeds/inspection_types.rb
) with any assignment changes (seeassignment_categories
attribute on each row) - Run
bundle exec rake db:seed:inspectors
. This task should be idempotent, as it usesfind_or_create
for existing inspector records. - Run
bundle exec rake db:seed:inspection_types
. This task should be idempotent, as it usesfind_or_create
for inspection types, and recreates theassignments
table from scratch each time. - Manually delete any inspectors that might no longer be needed (e.g. if they no longer work at the City). The seeds don't delete inspectors for data safety reasons.