Docker containers wrap a piece of software in a complete filesystem that contains everything needed to run: code, runtime, system tools, system libraries – anything that can be installed on a server. This guarantees that the software will always run the same, regardless of its environment. Docker - What is Docker?
The latest Docker downloads and setup instructions for your operating system can be found in the Docker downloads page.
Build the Bizport docker image:
$ docker-compose build
First, spin up the DB docker image:
$ docker-compose up db
Next, access the command line of the Bizport DB docker image:
$ docker exec -it bizport_db_1 /bin/bash
Switch to the postgres
user:
$ su postgres
Create your dev and test databases at the command line with the postgres shortcut createdb
:
$ createdb bizport_development
$ createdb bizport_test
Close/terminate your bash sessions.
Next, setup the database via rake:
$ docker-compose run web rake db:setup
There are two options for loading seed data: fixtures or a production database import. Fixtures are more portable if you're setting up on a computer without access to the production Heroku account. Importing direct from the Heroku account is likely to produce an environment with better production parity, and is the recommended approach.
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, access the command line of the Bizport DB docker image:
$ docker exec -it bizport_web_1 /bin/bash
Next, login to Heroku with your account credentials:
$ heroku
Then begin the database copy with:
$ heroku pg:pull DATABASE_URL bizport_development
Note that you may be prompted to drop your local database before pulling the new one. Also note that DATABASE_URL
is the default name for the main DB URL of a Heroku application. If this doesn't work, you can use heroku pg:info
to check the correct URL name for your database.
In order to load the bizport
CMS fixtures, the CMS needs to have a Site
object in the DB called bizport
with which to associate the fixtures. To do this, open the Rails console and add a site object with the site name.
$ docker-compose run web bundle exec rails console
> Comfy::Cms::Site.create(identifier:'bizport')
Close/terminate the web
image bash session.
Import fixtures.
To import CMS fixtures: docker-compose run web bundle exec rake comfortable_mexican_sofa:fixtures:import FROM=bizport TO=bizport
To export CMS fixtures: docker-compose run web bundle exec rake comfortable_mexican_sofa:fixtures:export FROM=bizport TO=bizport
To copy CMS fixtures from remote to local: docker-compose run web scp -r <username>@<host>:<path/to/app/folder>/db/cms_fixtures/bizport db/cms_fixtures/
You should now be able to boot the application by running docker-compose up
or docker-compose up web
if the db
container is already running. Visit localhost:3000
to verify that everything is working. The homepage uses a blend of code and database content to render, and so is a fairly complete test that everything is set up correctly.
Heroku's Container Registry and Runtime is a service specifically for deploying Docker containers. BizPort's docker-compose file specifies two containers, web
and db
, but Heroku will simply connect the web
container to its hosted DB service, so we only need to deploy the web
container.
If this is the first time you're using Heroku's container service, you'll need to install the plugin with heroku plugins:install heroku-container-registry
Further setup instructions, if needed, are available at https://devcenter.heroku.com/articles/container-registry-and-runtime
Log in to Heroku's Docker container registry: heroku container:login
The application can then be deployed with heroku container:push
That's it!
Homebrew is a package manager for system-level packages, and will help with installing a few libraries throughout the setup process. It can be installed by following the instructions at http://brew.sh/. On certain versions of OSX, or if you've recently updated from an older version of OSX or Homebrew, you might have some permissions issues. This article may be helpful: Homebrew/legacy-homebrew#17884
BizPort specifies Ruby version 2.3.0 (in the .ruby_version
file). To use a specific version of Ruby, you'll need a version managment package like rvm
or rbenv
. While either will work, we recommend rbenv
.
To install rbenv
, follow these instructions exactly. https://github.com/rbenv/rbenv#homebrew-on-mac-os-x
After rbenv has installed, navigate to the Rails project's root directory (bizport) and source your bash profile in the shell. If you don't have postgres installed, do so by using brew install postgres
or another installation method of your choice (e.g. Postgres.app). (Follow instructions here: https://launchschool.com/blog/how-to-install-postgresql-on-a-mac)
Create your dev and test databases at the command line with the postgres shortcut createdb
:
$ createdb bizport_development
$ createdb bizport_test
BizPort (more specifically, the CMS) uses the system package Imagemagick to compress and store uploaded images.
$ brew install imagemagick
Rails uses Bundler (http://bundler.io/) to manage gem dependencies. Simply cd
into the directory where you cloned this repo and run:
$ gem install bundler
$ bundle install
There are two options for loading seed data: fixtures or a production database import. Fixtures are more portable if you're setting up on a computer without access to the production Heroku account. Importing direct from the Heroku account is likely to produce an environment with better production parity, and is the recommended approach.
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, install the Heroku CLI tool:
$ brew install heroku
Then cd
into the repo folder and begin the database copy with:
$ heroku pg:pull DATABASE_URL bizport_development
Note that you may be prompted to drop your local database before pulling the new one. Also note that DATABASE_URL
is the default name for the main DB URL of a Heroku application. If this doesn't work, you can use heroku pg:info
to check the correct URL name for your database.
In order to load the bizport
CMS fixtures, the CMS needs to have a Site
object in the DB called bizport
with which to associate the fixtures. To do this, open the Rails console and add a site object with the site name.
$ bundle exec rails console
> Comfy::Cms::Site.create(identifier:'bizport')
Import fixtures.
To import CMS fixtures: bundle exec rake comfortable_mexican_sofa:fixtures:import FROM=bizport TO=bizport
To export CMS fixtures: bundle exec rake comfortable_mexican_sofa:fixtures:export FROM=bizport TO=bizport
To copy CMS fixtures from remote to local: scp -r <username>@<host>:<path/to/app/folder>/db/cms_fixtures/bizport db/cms_fixtures/
You should now be able to boot the application by running bundle exec rails server
or simply bundle exec rails s
. Visit localhost:3000
to verify that everything is working. The homepage uses a blend of code and database content to render, and so is a fairly complete test that everything is set up correctly.
As with all Rails apps, config/routes.rb
defines the way that routes are initially dispatched to controllers. Routes are read from top to bottom, with the first match taking precedence, and routes further down the file having lower priority. In BizPort, routes.rb
contains a few types of routes:
- "Static" routes that serve
haml
templates, managed by the StaticController. In spite of the name, these pages may still contain some dynamic content. - CMS routes (e.g.
comfy_route :cms_admin, path: '/cms'
), which delegates to the CMS for individual page lookups - Devise routes (e.g.
devise_for :users
), which delegate to thedevise
gem for user accounts/authentication/etc. - API routes (e.g.
put '/checklist'
), which provide an interface for front-end libs like React to modify DB records.
These routes call StaticController, which will look for a template with the same name as the controller method called. I.e. a request for static#home
will cause it to look for home.haml
.
These paths are defined by creating pages in the CMS. Note that the CMS routes are placed near the bottom of routes.rb
so that any named routes above will take precedence over CMS content.
Devise defines a set of default controllers for most things you'll want to do with users, signup, and login. In most cases, therefore, declaring devise_for :users
to load the default routes is sufficient. Refer to the Devise docs for instructions overriding routes and controllers.
Serving as endpoints for the React portions of the site (/profile
page at this point), these routes are approximately RESTful, but are probably ripe for some rearchitecting as the app grows and matures.
By Rails convention, all pages inherit by default from the site's master layout, views/layouts/application.haml
. Consequently, this layout includes components present on every page like the sidebar, analytics code, and <head>
<meta>
tags. Child templates (i.e. pages that use this layout) are rendered at the = yield
statement.
The CMS has the ability to manage layouts as content (rather than code), but can also use code-based layouts, and include template partials inside CMS pages. All CMS pages must inherit from a root code-based layout - in BizPort, this is always application.rb
.
For any given CMS page, the path of template/layout inheritance can be traced by the following steps:
- In the CMS Pages editing interface, look at the "Layout" property for the page
- In the CMS Layouts editing interface, find the relevant layout. If the layout has a "Parent Layout", go to that parent layout and repeat this step.
- When you find a layout that does not have a "Parent Layout" value, look at the "App Layout" value. This is the name of the
html.haml
file in the codebase that is serving as the root layout. N.B.: As ofcomfortable_mexican_sofa
1.12.9
, this file must containhtml
in the file extension in order for the CMS to recognize it. This appears to be a bug, and is tracked in comfy/comfortable-mexican-sofa#734
Code-based partials can be included in pages with a special tag that the CMS provides: {{ cms:partial:shared/partial_name:param_1:param_2 }}
. While it's possible to pass arguments to partials, these arguments cannot be named, and are simply called param_1
and param_2
. As a result, partials like shared/_checklist.haml
often use the pattern - category ||= param_1
at the top of the file to name these params when they're passed in from the CMS. More documentation on these types of CMS tags is available in the gem's wiki.
Some parts of the application - the checklists and profile page in particular - rely on custom-structured content like checklists and form fields. This content is managed outside of the CMS, and can be viewed and edited via the ActiveAdmin interface at /admin
.
In order to allow users to edit their checklist and notebook on their Profile page without refreshing the page on each save, BizPort uses a front-end MVC framework, React, to make calls to an API for each user edit. React was chosen because, at time of writing (October 2016), it had a strong user base, was likely to continue to be supported for the next several years, provided an easy way to pre-render the page on the server (which helps with accessibility, slow internet connections, etc.), and seemed like a generally way to write modular JS.
User accounts (signup and login) are managed with Devise, which is the most-used Ruby authentication gem. So far, the app only uses the email/password form of authentication, but modules are available for all manner of OAuth connections like Facebook and Twitter.
To log in to the CMS, first visit /admin
and enter your username and password. If you're already able to view the "dashboard" (should have a couple of graphs/charts on it) at /admin
, then you're logged in! Once you're in, change the URL to /cms
to get to the CMS editing view.
Youtube video embed: {{ cms:partial:shared/video_embed_youtube:"https://www.youtube.com/embed/3ZtdlSmlC44" }}
{{ cms:partial:shared/link_box:"https://paydirect.link2gov.com/LBCbuslicense/ItemSearch":"PAY":"Renewal Fee Online" }}
{{ cms:partial:shared/location_map:"SBDC: Downtown Long Beach Office":"309 Pine Ave, Long Beach, CA 90802" }}
{{ cms:partial:shared/contact_box_combo:"(562) 570-6211":"LBBIZ@longbeach.gov" }}
{{ cms:partial:shared/contact_box:"phone":"(562) 570-6105" }}
{{ cms:partial:shared/contact_box:"email":"test@example.com" }}
<div class='callout'>
NOTE:
</div>
To make a section of content collapse if it goes beyond a certain height (presently set at 600px), simply add the class readmore-section
to the div wrapper for that content block.
Example:
<div class='readmore-section'>
<h2>Title of This Section</h2>
<p>Copy for this section.</p>
</div>
Each contact accordion section (for a particular agency, department, etc.) is created with the following code:
<ul class="accordion modules" data-accordion="true" data-allow-all-closed="true">
<li class="accordion-item modular-box" data-accordion-item="true">
<a class="accordion-title step-group-title text-centered">
<div class="step-group-title-text">
<div class="text">
<strong>Long Beach City Hall</strong>
<div>Protects citizens through legal enforcement</div>
</div>
<div class="arrow"></div>
</div>
</a>
<div class="accordion-content" data-tab-content="true">
{{ cms:partial:shared/modular_box:'phone':'562-570-6555' }}
{{ cms:partial:shared/modular_box:'hours':'7:30am-4:30pm M-F' }}
{{ cms:partial:shared/modular_box:'map':"333 W Ocean Blvd, Long Beach, CA 90802" }}
{{ cms:partial:shared/modular_box:'bus':"Metro Blue Line" }}
{{ cms:partial:shared/modular_box:'bike':"Bike racks and bike share pods available." }}
{{ cms:partial:shared/modular_box:'parking':"Parking is available at 332 West Broadway Avenue; the first 30 minutes are free, and each additional 20 minutes cost $1.25, with a maximum fee of $7.50. Metered parking is also available along Broadway and Cedar, directly in front of City Hall." }}
</div>
</li>
</ul>
Currently supported content types are phone
, email
, hours
, map
, bus
, bike
, parking
. Note that content with line breaks (e.g. a list of different daily hours) is not supported with this module. If a particular section needs multi-line content, the module ({{...}}
) can be replaced with the following HTML:
<div class="contact-pane">
<div class="contact-pane-section">
<i class="icon icon-hours"></i> <!-- note that the class name here determines the icon -->
</div>
<div class="contact-pane-section">
<!-- YOUR CUSTOM HTML HERE (e.g. list <ul> items) -->
</div>
</div>