March 5, 2020

Configuring a Heroku Review App to use another apps database

In certain scenarios, I’ve found it useful to use our production app’s Read Replica as a source for manual testing. It’s not something I’m reaching for often but there are definitely cases where our seed data just doesn’t cut it.

Since it’s a read replica, no writes can be made to it and I don’t have to worry (too much) about harming production. You’ll want to make sure any external user operations aren’t configured to happen automatically (e.g. sending email, cropping avatars, etc).


In order to assign a different DATABASE_URL to a review app, you’ll need to destroy the postgres attachment on your review app. I knock this out by chaining some commands together:

heroku addons:destroy $(heroku addons:info heroku-postgresql -a your_review_app | grep '===' | awk '{print $2}') -a your_review_app

The sub-command here is getting the name of the add-on (e.g. postgresql-concentric-04442) and passing it to heroku addons:destroy.1


Now that we’ve gotten rid of that pesky, old database, we can set the DATABASE_URL on our review app. I also have a banger of a command for this:

heroku config:set DATABASE_URL="$(heroku config:get HEROKU_POSTGRESQL_PURPLE_URL -r production)" -a your_review_app

In order to know what to substitute in for HEROKU_POSTGRESQL_PURPLE_URL in your setup, run:2

heroku pg:info -r production | grep Followers 

Use your discretion to determine your read-replica.


That’s it. In my case, my app was rebooted and it read the DATABASE_URL without a problem. If your app tries to do writes, it will most likely throw an exception.

  1. Of course, don’t put your production app’s name in this one. 😂😱

  2. Assuming you’re using a read replica from Heroku

March 3, 2020

Resolving Brakeman Errors

After running brakeman you’ll get a report and, if there are new warnings, it will exit with a status code of 3”. Typically, I only see two types of output from Brakeman. Either a large report where there are new warnings or a short report which is saying Brakeman is out of date.

I’ll briefly explain resolving both.

Resolving New Warning(s) Detected

The long report.

Run brakeman -I to get an interactive console for ignoring warnings. It will analyze your code base and then prompt you for where to find the ignore file. I’ve always used the default location of config/brakeman.ignore, so I simply press Enter to accept the default.

Then I almost always choose option 2 to Hide previously ignored warnings”. This option is a bit confusing. It’s the same as option 1 but doesn’t show warnings you’ve already ignored.

At this point, brakeman will iterate over each new warning prompting you to ignore the warning. This is a critical point in your role here. You need to make sure the warning should be ignored or fixed. If this is a positive warning, you need to Ctrl-C right now and go fix the code rather than ignoring the vulnerability. If it is a false-positive, you can ignore it here via i or n. I recommend n because it prompts for a note as to why this warning is a false-positive.

After you have resolved all warnings, it will (optionally) prompt you to remove fingerprints (outdated warnings). You need to input y or yes here for it to actually remove the fingerprints.

Finally, you’ll want to save changes via 1 and, due to amnesia or disorder, Brakeman will again ask you where the ignore file is. I again just press Enter because I use the default location. (I have no idea why the input and output would be in different locations.)

You can run brakeman again and it should report No warnings found”. You’re all ready to check the ignore file into source control and push it up to your CI.

Brakeman’s Out of Date

The short report.

This only appears if you’re running brakeman --enusre-latest (which I highly recommend).

To fix, simply run bundle update brakeman. This will update your Gemfile.lock which is all you should need to change.

If you are locking brakeman in your Gemfile (which I don’t recommend), you should check Brakeman’s CHANGES to make sure the new changes don’t break whatever you’re guarding against with the version locking.

January 28, 2020

Audio Gear

If you would like to have great, clean sounding audio in your meetings, podcasts, or videos. Purchase the microphone and audio interface that I recommend and use below.


I use the Audio-Technica AT875R shotgun microphone.

I place it 3-5 inches from my mouth using a boom arm attached to my desk. Since I type on that desk, I use a shock mount.

Since this is a shotgun mic, it works great from a distance. I can position the mic about 6-8 inches from my mouth to get it out of a video head shot which I use for meetings (I have enough room for a lower third with this shot; about a 35mm focal length). But, for best sound, place it only a fist-full away.

Audio Interface

Since most microphones in this category do not have USB, you will need an interface to connect it to your computer.

I recommend the Behringer UMC204HD audio interface. I have the 404HD which has four inputs instead of two. I have yet to use more than two inputs though.

Many podcasters like the Focusrite Scarlett interfaces but these cannot be muted by apps like Shush (see below) and therefore I cannot recommend them.

Boom Arm

The microphone I recommend doesn’t come with a stand. In my setup, I have a Rode PSA1 Boom arm. It’s fine but if it ever breaks I’ll probably purchase a Blue Compass purely for asthetics. Neewer makes a cheap boom arm but I haven’t tried it.

Shock Mount

Since I’m typing/bumping the desk I sit at, I got a shock mount which works great with my microphone.

XLR Cable

None of the aforementioned products come with an XLR cable. If you’re using a boom arm you will probably need 6-15ft of XLR cable. I went with a 10ft cable from Planet Waves. I had a little cable to spare.

Shush - Digital Cough Drop

When you’re in a meeting or apart of a live event, you’ll eventually need to cough or sneeze or the dog starts barking or something else will happen, and you will want to mute your microphone quickly. For this case, I highly recommend the $5 app Shush from Mizage.

In Push-to-Silence mode, I have a single hot key that I can hold to mute myself. Great for using as a digital cough drop. Double-press my hot key and it switches modes. Now, in Push-to-Talk mode, I can hold my hot key to talk to my guests (great when I’m in a large group and I don’t need to talk a lot). Double-press it again and I’m back to Push-to-Silence mode.

I do recommend turning off the sounds Shush makes which means you have to rely on the status bar icon to know if you’re muted.

Monitoring Headphones

You’ll want some closed backed headphones if you are going to be recording audio for others to listen to. You’ll want closed backed headphones so that audio doesn’t leak into your microphone. I’ve heard good things about the Sony MDR7506. I personally use the Shure SE215 as they are in-ear monitors which aren’t so obnoxious on camera.

Too expensive for you?

Another option to all of the above is a USB microphone and some wired earbuds. The Audio-Technica ATR2100x-USB is a hand-held mic that comes with a stand. It has a standard headphone jack for audio monitoring and will work as an audio output so you can hear yourself and your computer’s audio in your headphones. It also has an XLR port so if you wanted to slowly upgraded into a boom arm, usb interface, and so on, you could do so without having to buy a new microphone. I haven’t used it personally.

(This could be a good mobile solution as well.)

Find yourself saying I have too much money” or I want more options”?

Check out Marco Arment’s Podcasting Microphones Mega-Review. He uses a $250 microphone with a $880 USB Interface and $1300 headphones with a $850 headphone amp.

While he does have pricey tastes, don’t let that steer you away from his mega-review. He reviews almost two dozens mics, ranging from $10-900, with multiple sound recordings from each. If you want to research this rather than take my opinion, look no further. And if you do, check out Podcastage’s YouTube Channel.

November 18, 2019

Hand and Wrist Exercises for Computer Users

I’ve been having problems with minor pain in my hands, wrists, and up through my arm. I’ve been giving these exercise a go.

October 28, 2019

Rails CDN and ActiveStorage

When serving assets and attachments from Rails and ActiveStorage, a CDN is a great way to reduce load on your web server and speed up content delivery to your users.

Asset CDN

First, even if you’re not using ActiveStorage, you’ll want to set up a CDN to stand in front of your app. This will proxy requests for images, fonts, javascripts, and stylesheets that live in your app’s repository.

The ideal setup here is to serve your assets from your app, set a high cache-expiration, and serve your assets through a CDN.

Setting up your Asset CDN

For a CDN, I recommend Amazon CloudFront. You’ll want to create a web distribution which points at the root of your app. Heroku has a good guide on that.

Once it’s set up, set an environment variable1 (e.g. ASSET_HOST) to the distribution domain name and configure your asset_host. Also, set a long expiration for your assets. In config/environments/production.rb 2 3:

# Tell our CDN and browser to cache assets for a year.
config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=31536000' }

# Serve images, stylesheets, and javascripts from an asset server.
config.action_controller.asset_host = ENV['ASSET_HOST']

Once you’ve configured the above, your production assets should serve from your CloudFront CDN.

For more information, on serving assets, caching, and cache invalidation, see the Rails Guides.

ActiveStorage Attachments served through a CDN

When you serve attachments from a cloud storage service (I’m using S3), it will be coming from a different domain than your app. One solution to this would be to stream the file contents through your app.

I opted for creating a second CDN distribution that sits in front of the cloud storage provider that ActiveStorage serves for its 302 redirect 4. This does require a little configuration. Thankfully nothing needs to be monkey patched.

  1. Create a second CloudFront web distribution that points to your S3 bucket and point your ATTACHMENT_HOST env variable at it (prepended with https://).
  2. In lib/active_storage/service/s3_directory_service.rb, create the service in this gist.
  3. In config/environment/production.rb, set ActiveStorage’s service_urls_expire_in :

    # Tell our CDN and browser to cache attachments for a year.
    config.active_storage.service_urls_expire_in = 1.year
  4. In config/storage.yml, configure the service and default cache_control for uploaded attachments by adding the upload key 5:

      service: S3Directory
      # ...
        cache_control: 'public, max-age=31536000'
  5. When linking to the attachments, use the rails_blob_url helper like so: 6

    rails_blob_url user.avatar, host: ENV['ASSET_HOST']

    (For variants, you’ll need to call rails_representation_url instead.)

Now your ActiveStorage attachments will serve through the two CDNs: the first request will hit Rails’ Representations or Blob controller (through the Asset CDN) which will redirect to the service url for the attachment (through the Attachment CDN). If this attachment has been served to a previous user, no request will hit your web server as CloudFront will have it in its cache. If that user has requested the attachment before, it well be served from the browser’s memory and no request will be made.7

  1. Prepend the host with https://.

  2. If you’re using Heroku Review Apps, you’ll want to conditionally use ENV['HEROKU_APP_NAME'] based on ENV['HEROKU_PARENT_APP_NAME'].

  3. You may also want to set your mailers’ asset host.

  4. See Rails’ Representation and Variants controller to see how that works.

  5. If you already have ActiveStorage attachments uploaded in production, you can make them public and add a cache-control header by using aws cli tools.

  6. You may want to create a helper method to make this a little cleaner.

  7. The same is true for your assets and the Asset CDN.

October 24, 2019

MacBook Pro Battery Drain

My main computer is my iMac. It seemed like every time I opened my MacBook Pro, it would show this screen:

MacBook Pro showing low battery full screen

So I researched a bit and fixed it. Here’s what I did:

  • Turn off PowerNap while on battery power”. This is the Energy preference pane.
  • Turn off Allow Bluetooth devices to wake this computer”. This is in the Bluetooth preference pane under Advanced.

That’s it.

Now, when I open my MacBook the battery has barely moved from the previous day. For example, 3 days ago I closed my laptop with 64% battery. I opened it this morning with 50% battery. A 5%/day battery drain is excellent for a computer that’s keeping its running memory actively powered. Previously I’d see what seemed to be 5%/hour (I didn’t actually measure it but rarely did I open my laptop and it wasn’t dead).

If you want to track your battery usage, check out iStat Menus. It has a graph to show battery drain over time (past hour, day, week, month).

iStat Menus Battery Screenshot

Mac Tips