Express Sequelize Heroku Postgres Configuration Success

You are in flow developing on your local database and you decide to upload everything to heroku and share it with the world.

How do you configure your production database?

Its easier than you think. Lets assume you have already set up your site. (link)

If you used the sequelize init command, you will have a file db/models/index.js that looks like this

Usually, your sequelize database will initialize with the usual database, username password, etc but in the special case that your config has use_env_variable, sequelize will recognize that an environment variable (usually representing a URI) can be used in place of the usual credentials.

What is your env variable?

After you run heroku addon create ... a new environment variable will be created at your heroku application

Find this in your heroku settings or running $ heroku config

You can access this with process.env.DATABASE_URL in any of your node.js code (on production). Your local machine will have different environment variables set.

Step 1: Set use_env_variable

But set it to what? Set it what heroku designates as your database url, DATABASE_URL!

Thats it!

You may need to migrate your database if you aren’t using sync

Step 2: Migrate your database

Error: no pg_hba.conf entry for host…, SSL OFF

you need to set TWO attributes to specify ssl

Error: The server does not support SSL connections

So tried to migrate your empty production database by setting the correct environment variables for the command and running db:migrate

$ NODE_ENV=production DATABASEURL=<db_url> sequelize db:migrate

How do you set up your local machine to support SSL?? You could get a certificate and configure your sequelize config to use that BUT theres an easier way.

Simply run the command in the heroku environment

$ heroku run ./node_modules/.bin/sequelize db:migrate --debug

Node Sequelize Postgres Tutorial

Why?

Sometimes you want your team to use an ORM.

Setup

Step 1: Create your npm project

$ npm init

Step 2: Install the packages

$ npm install --save sequelize sequelize-cli pg pg-hstore

Step 3: Create a new database

Lets create a local database (this depends on your target). If you have postgres installed use:

$ createdb user-demo-db

Step 4 : Create a .sequelizerc file

This will be used by sequelize for determining which paths to create directories

var path = require('path')

module.exports = {
  'config': path.resolve('config', 'config.js'),
  'migrations-path': path.resolve('db', 'migrations'),
  'models-path': path.resolve('db', 'models'),
  'seeders-path': path.resolve('db', 'seeders'),
}

* we are using config.js because javascript will allow us to access environment variables. We will typically not want to store password sensitive strings in our production app.

Step 5: Initialize your sequelize directories

$ node_modules/.bin/sequelize init

Step 6: Fix config.js

Since we used .js instead of .json we have to:

  1. edit our config file to export our object
  2. Your generated sequelize index.js file will default to using the development database so change development database field to the name of your database user-demo-db 
  3. Change your username to your system username (probably not root)
  4. Also make sure to change the dialect to postgres

* later, we will want to use environment variables to access passwords

Now what? Using Sequelize

We can either create our database tables with the psql shell using raw queries or we can use sequelize to manage our database.

In this article we will use sequelize and if we do, we now have two options: 1. Using sync or 2. Using migrations.

In most tutorials you will see code using sync() or even sync({force: true}). This is completely fine in a test database as it will completely overwrite changes you make in your “model” files.

We will use migrations for one big reason. Migrations will create “migration files” for all database changes where we can get valuable source controlled information.

Step 7 : Create your first model by generating your first migration files

Here we are creating a new model by generating both the initial model file AND the migration file for a sample model User with some attributes firstName;lastName;email

* Note: we are using the singular “User” and not the plural “Users”. This will be an ORM convention that you will need to get used to.

$ node_modules/.bin/sequelize model:generate --name User --attributes firstName:string,lastName:string,email:string

Look inside your new model file: 

It should export a new “model” using sequelize.define("User", ...) with the attributes that you specified in the command line arguments.

* Note that the default id field is INTEGER and not something cool like UUID, its your code now, you can change this.

Look inside your new migration file:

It should use the  queryInterface function  createTable('User', ...) with attributes that you specified in the command line arguments plus three fields that sequelize will add to every table id, createdAt and updatedAt

* One thing that is key to note is that by default you table name is pluralized

Step 8: Run the migration

Before you run this migration, you may change the migration/model file to edit your attributes.

$ node_modules/.bin/sequelize db:migrate

Sequelize will create a SequelizeMeta table in your database to keep track of which migrations have been run. That also means you can create many other models before running this command and it will run all not-yet-run migrations

Check your migration

After you run your migration you can check your table status with psql shell or pgadmin

$ psql user-demo-db

psql> \d "Users" <- note the “s”; note the double quotes 

Get used to this pattern, you will use this a lot.

(Optional) Create an instance of your model – User

Note that we use the singular User instead of the Users from the actual table

node> var models = require('./db/models')

node> models.create.User({

  firstName: "John", lastName: "Doe", email: "jd@gmail.com"})

Step 9: Create a 1:Many relationship

Lets create a model called Task that can only have one User. 1(User):Many(Tasks).

Create your migration files and migrate your database to add the new table

$ node_modules/.bin/sequelize model:generate --name task --attributes body:string,done:boolean

$ node_modules/.bin/sequelize db:migrate

Now we will need to associate the Task to the User in some way.

According to the docs we need to run Task.belongsTo(User)

However if we add this to the db/models/Task.js file in the associate function, our file now fails to load correctly when accessing db/models within the node shell. We can open up our node shell and do this manually.

node> const models = require('./db/models')

node> models.Task.belongsTo(models.User)

What happened?

BelongsTo associations are associations where the foreign key for the one-to-one relation exists on the source model.

– docs

We ran the code <source>.belongsTo(<target>) with having the appropriate “foreign key” on our source model (Our Task model is missing the column UserId). Instead of undoing our migration, this is a perfect time to learn how to do a database migration.

Step 11: Fix our 1:M relationship

This time we only need the migration file, and not the model generated file.

$ node_modules/.bin/sequelize migration:generate --name add_userid_to_task

Adding a foreign key field to a model – Task

We want to create a new column UserId on our Task model/table that represents a foreign key relationship. The docs explain that all we need is a references key with the correct values

Your migration file will look something like this: code

return queryInterface.addColumn(
  SOURCE_TABLE_NAME,  // "Tasks"
  TARGET_FIELD_NAME, // "UserId"
  {
    type: Sequelize.INTEGER,
    reference: {
      model: TARGET_TABLE_NAME, // "Users"
      key: "id"
    }
    onDelete: 'cascade
  }
)

Important Notes:

  • we have to match the type of the target field (“integer” in our case above, “UUID” if you wanted to create an advanced User model)
  • Your source “table” name is likely the plural version of your “model” name. You can get the model name with node> require('../models')[model_name].getTableName()
  • Your target field name should be “title-case” based on sequelize convention, so if you’re targeting id on User, your target field name is UserId

Step 12: Remember to migrate your database!

$ node_modules/.bin/sequelize db:migrate

 

Resources:

Code Sample

Docs

How to define Sequelize associations using migrations

How does sequelize pluralize?

If you use .sync with sequlize and have a model name like User, your database ends up with a table called Users. More clearly, when you use the sequelize-cli model generator the generated file will show this pluralized table. Here is the code: (link)

What is Utils

* Note Sequelize has a directory called Utils AND a file at lib/utils.js.

What’s in lib/util.js?

 

We find the function! This is how sequelize defines utils.pluralize link

Util.pluralize IS inflection.pluralize

This is how its tested 

What is inflection?

Inflection is a port of Ruby on Rails Active Support Inflection classes into JavaScript built by DreamersLab in Taipei. (link)

So how does sequelize/inflection pluralize?

Inflection seems to have rules based on:

Eventually, inflection takes these rules, uses RegExp and applies them to your string. Theres a bunch of rules and at the end theres this

The common rule that is the exhausted else or case default rule that targets the end of the string with $. No rules for that singular term? Add an s

Postgres timestamp with timezone – “timestamptz”

Postgres can store your timestamp WITH or WITHOUT timezone.
If you don’t specify either, it will default to “timestamp without timezone”

Which one should you use? TLDR: “timestamps with time zones”

Whats the problem living life without timezones?

Say you have two users in two different timezones – one in California and one in France. Imagine you may need to know which one acted “first”, maybe in an auction or draft scenario where the whoever acts first wins.

Without specifying timezone, your database will save the plain timestamp of each user, say “midnight” and “midnight”. How will you know which one acted first?

You could save the original timezone from the user and perform the necessary algebra when needed.

Solution – Use “timestamp with time zone” otherwise known as “timestamptz” 

For timestamp with time zone, the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT). An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone. If no time zone is stated in the input string, then it is assumed to be in the time zone indicated by the system’s TimeZone parameter, and is converted to UTC using the offset for the timezone zone.

Postgres docs

This bears repeating: 

“For timestamp with time zone, the internally stored value is always in UTC.”

A proper name for this might be timestamp saved as UTC by default. By saving everything in the “same” timezone, we know the absolute time of the timestamps.

This brings up the main UX concern: What do users see?

Your users want to read data from the database using their preferred timezone.

(If they added a blog post at 3:00pm PST, they want to see the timestamp as 3:00pm not, )

Dates are saved as UTC so you will eventually need to convert the time

Converting on the server:

Best practice is to save the users’ preferred timezone as a name (e.g. America/Los_Angeles). This way your query or ORM can convert the date according to user preference.

Remember, timezones offsets are affected by political actions. A timezones actual hour offset can change depending on whether the timezone recognizes daylight savings time or just simply when the political “owners” of the timezone decide to CHANGE the offset. Read The Long, Painful History of Time for more info.

Converting on the browser:

Many browsers have default timezones that can be used by passing in your date to new Date. You can also, simply use moment.js to parse the dates on the client to show the correctly formatted date string for your purpose.

What about user input?

User input should always be converted to UTC. Many functions already return UTC by default such as  new Date() in Browser JavaScript and node.

 

Resources:

PostgreSQL Data Types: Date, Timestamp, and Time Zones

Detecting the time zone from the browser: 

Using CAShapeLayer to draw a circle

UIViews are like Ogres, which are like onions – they have layers.

Source: Documentation

More accurately, UIView has a single layer property that can have infinite sublayers.

UIView’s have layers

Lets draw a circle.

First create a UIView and a CAShapeLayer:

let myView = UIView()

let myLayer = CAShapeLayer()

Layers have a path

UIBezierPath makes drawing shapes extremely smooth, lets say in the shape of a circle:

let circlePath = UIBezierPath(
  arcCenter: CGPoint(x: 100.0, y: 100.0),
  radius: 100,
  startAngle: 0 * CGFloat.pi / 180,
  endAngle: 360 * CGFloat.pi / 180,
  clockwise: true)

Great! Now we can add CAShapeLayer as a CGPath and spruce up our fill and stroke colors

myLayer.path = circlePath.cgPath
myLayer.strokeColor = UIColor.blue.cgColor
myLayer.fillColor = UIColor.yellow.cgColor

Last step! Add this layer to your UIView

myView.layer.addSublayer(myLayer)

Layers have attributes

strokeColor,fillColor, opacity, lineWidth and more!

Bonus: Layers can animate attributes

// create the animation
let opacityAnimation = CABasicAnimation(
  keyPath: #keyPath(CALayer.opacity))
opacityAnimation.fromValue = 0
opacityAnimation.toValue = 1
opacityAnimation.duration = 5.0

// set the final value; add the animation
myLayer.opacity = 1
myLayer.add(opacityAnimation, forKey: #keyPath(CALayer.opacity))

iOS Application Lifecycle – UIKit basics

iOS applications are all about cycles

This is because the iOS applications are richly interactive when it comes to user input and much of your programming with UIKit will be delegate oriented. Knowing the many different “cycles” of the device and application will be illuminating for your development.

States of the UIKit App Cycle

* These are the execution states of a UIKit app from the Apple docs. But why so many arrows? Below is the simplified flow charts

User Action: Your app has not been launched

Your application starts off Current State: Not Running

User Action: Your app is launched

Delegate method called: application(_:didFinishLaunchingWithOptions:)

New state: Inactive – your application is briefly here as it prepares a successful launch

New state: Active – your application is now the “foreground app”.

Many apps will place a majority of the app setup logic in this function including setting up a programmatic view controller setup (bypassing the default storyboard)

Delegate method called: applicationDidBecomeActive

User Action: User goes to home screen or opens another app

 

Current state: Active

Delegate method called: applicationWillResignActive

New state: Inactive – your application is briefly here

New state: Background – your app is available in the app picker screen on home button double tap

Delegate method called: applicationDidEnterBackground*

* If your app does not support background execution “applicationWillTerminate” is called

** If your iOS device is low on memory, it may suspend and even terminate your app back to the state “Not Running”

User Action: User reopens a background app

Current state: Background

Delegate method called: applicationWillEnterForeground

New state: Active

Delegate method called: applicationDidBecomeActive

 

TLDR: Your basic UIKit flow moves from Active <-> Background

These are only the basic lifecycle events for your UIKit app, there are MANY different scenarios that can change the state of your app – the device can span a low battery warning and show the power saving alert, a phone call may occur, users can click and hold notifications, the device can run out of batteries.

iOS without storyboard

Why?

Programmatically/Code or NIB based layouts are a much better fit for projects that use version control (see merge conflicts) and make it much easier to reuse views.

Step 1: Delete Main Interface from Deployment Info Settings

Step 2: Delete the Main.storyboard file

Step 3: Manually prepare and set the window property in AppDelegate.swift

Step 3a: Create a new UIWindow to the main UIScreen bounds

Step 3b: Make your window “key”

Step 3c: Set your window rootViewController to the ViewController of your choice

Code: link

Forgetting to set translatesAutoresizingMaskIntoConstraints to false

UIKit on iOS is great! There are tons of tools and often this can supercharge your productivity for getting a prototype out into the world.

Additionally, working with AutoLayout programmatically can be great if you avoid these rookie mistakes.

Rookie Mistake 1:

It hurts when you spend hours dealing with the rookie mistake of forgetting to set translatesAutoresizingMaskIntoConstraints to false on the view when setting constraints.

view.translatesAutoresizingMaskIntoConstraints = false

Rookie Mistake 2: 

Remember that you also have to also set your NSLayoutConstraint to true

Example:

yourView.centerXAnchor.constraint(equalTo:
  view.centerXAnchor).isActive = true

Solution:

This function allows you to program with wild abandon! If you use this function to set your constraints you never need to remember those pesky settings.

func setLayoutConstraints(
    view: UIView,
    constraints: [NSLayoutConstraint]) {
        view.translatesAutoresizingMaskIntoConstraints = false
        constraints.forEach({constraint in
            constraint.isActive = true
        })
}

Code found here, and more

*Update: Apple created a convienance method on NSLayoutConstraint called .activate that will set the isActive property to true. The new code would look like this:

func setLayoutConstraints(
    view: UIView,
    constraints: [NSLayoutConstraint]) {
        view.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint(constraints)
}

Delete files by filename with “find”

When you upload photos multiple times, the computer can start numbering the photos. IMG_A becomes IMG_A 1 and IMG_A 2 and IMG_A 3.

Using a wildcard * and specifying the ending space and number will help you select the files. For example:

Find all the files that end in "space"1.JPG

find -name '* 1.JPG'

* Have a look at the returned files to make sure you want to delete these

Find AND DELETE all the files that end in "space"1.JPG

find -name '* 1.JPG' -delete

gist