Matthew Lindfield Seager

novice designers are best served by writing test-first code. Their lack of design skills may make this bafflingly difficult but if they persevere they will at least have testable code — Sandi Metz in POODR

I think I’m just starting to get past the bafflingly difficult stage!

Reason # 1,562 that I love Ruby (and the frameworks it has fostered):

ActiveSupport::Duration has plurals of duration methods so 1.hour and 2.hours both work.

Enjoyed hearing the emphasis on simplicity and speed of deployment on the latest Ruby Rogues episode.

I love using Heroku to speed up deployment and feedback but I’m also keen to learn more about where Dokku and Beanstalk (different to the AWS product!!!) might fit in.

New Rails App Checklist

I run up a new Rails app often enough that I have a certain way I like to do things, but infrequently enough that I normally have to spend a bit of time on Google/Stack Overflow remembering how to do it that way. This checklist is my attempt to remedy that.

Latest Ruby Version

If I’m starting a new project I want to be starting with the latest (usually stable) ruby.

  • Ensure rbenv up to date: brew upgrade rbenv ruby-build
  • Check what the latest stable version is: rbenv install -l
    • 2.5.1
    • 2.5.2
    • 2.5.3 <- the highest one before dev/preview
    • 2.6.0-dev
    • 2.6.0-preview1
    • 2.6.0-preview2
    • 2.6.0-preview3
    • jruby-1.5.6
  • Install it (will prompt if already installed): rbenv install 2.5.3
  • Set it as global version (probably): rbenv global 2.5.3

Latest Rails Version

I also want it to be on the latest (again, stable) Rails.

  • Check latest version of rails: gem list rails --remote -e --all (-e for exact match, –all shows all versions, not just the latest… is optional)
    • rails (5.2.1, 5.2.0, 5.1.6, 5.1.5, 5.1.4, 5.1.3….
  • Install that version: gem install rails -v 5.2.1
  • Instead of the above two steps I can probably just use bundler conventions:
    • gem install rails to get latest
    • gem install rails -v '~> 5.0 to get latest 5.x.y version

Rails New

My philosophy (as a relative newbie) is to pretty much use Rails “The Rails Way” (the Basecamp way?). At this stage that means I don’t monkey with the default gems (with one exception), I just use the default test framework, javascript framework, etc initially. I do change my dev database to Postgres however.

  • Create new rails app without running bundle (about to modify it anyway) and with Postgres as database: rails new --skip-bundle --database=postgresql <app-name>
  • My one exception to default gems is switching to HAML which I like writing (and reading) so much more than ERB: add “gem ‘haml-rails’” to Gemfile
  • Run bundle
  • Convert the three default erb templates (application, html mailer and text mailer) to haml and choose yes when it asks if you want to delete the originals: rails haml:erb2haml

Setup Version Control

I use Github mainly due to inertia/convenience. I have tried Bitbucket, and like being able to hide my work in private repositories for free, but it’s probably good for me to develop “in the open” a bit more.

  • Create repository on github.com
  • git add .
  • git commit:
    • Initial commit
    • - Latest ruby
    • - Latest rails
    • - HAML instead of ERB
  • git remote add origin git@github.com:<user>/<repo-name>.git
  • git push -u origin master

And then?

Next steps should probably be along the lines of (not necessarily in this order):

  • Update the README so others (probably just future me) know what to do to get started
  • Add any additional steps to bin/setup?
  • Deploy to Heroku - for speed, convenience and cost (free while experimenting)
  • Start writing code

Possible Future Process Improvements

These are some things I might want to think about enhancing next time I use this checklist (or review this process).

  • Come up with a README template to reduce friction and make me more likely to get off to a good start
  • Maybe come up with a rails new template (passed in with -m)… or “specify extra command-line arguments to be used every time ‘rails new’ runs in the .railsrc configuration file in [my] home directory”
  • Not having to go to GitHub.com to create repository, the following command seems to work if using a personal access token with “public_repo” scope: curl -H "Authorization: token 12d3fd45f6ac7c89012345678db901ac2a3456f7" '[api.github.com/user/repo...](https://api.github.com/user/repos') -d '{"name":"test-repo"}'
  • Add heroku instructions/notes

Easily Paste Unstyled Text on the Mac

Most people know the basic keyboard shortcuts ⌘X, ⌘C and ⌘V for cut, copy and paste but, if you like to keep your hands on the keyboard as much as possible, an important related Mac keyboard shortcut to know is ⌘⌥⇧V (command-option-shift-v) for “Paste and Match Style” (or “Paste as Text” which is how I think of it).

Under the hood, Paste and Match Style simply pastes in the text only version of whatever is on your clipboard, thereby stripping out fonts, colours, sizes and other rich text formatting.

This can be useful when pasting styled text into Pages or Mail (for example), when you just want the raw text, not all the styles.

Another time it comes in handy is when copying and pasting links. If you right click on the Micro.blog “Timeline” link above and choose “Copy Link” you’ll get a rich text link on your clipboard. If you try and paste it into the body of an email message you’ll get the word “Timeline” linked to the url. If you just want the URL you can use ⌘⌥⇧V to “Paste and Match Style”, pasting just the unformatted URL.

Notes

  • This article is very Mac centric. Microsoft has probably copied implemented a similar feature on Windows
  • I tend to favour native Mac apps. If you use any cross-platform apps (such as Chrome, Atom or Slack) you’ll often find the equivalent shortcut in them is ⌘⇧V (no option key)
  • In my limited testing the Universal clipboard behaves a bit differently. It seems to favour sharing the unstyled text between devices (macOS to iOS or iOS to iOS). Your mileage may vary
  • For more information on how this all works under the covers, Apple’s developer documentation is very good… UIPasteboard for iOS and NSPasteboard for macOS
  • While looking for ways to view the raw pasteboard data on my Mac I stumbled across a fantastic TidBITS article which goes into a bit more detail and taught me about an additional pasteboard-like feature from the unix underpinnings called a kill-ring.

Nearly finished the Upcase Intermediate Rails course. Last lesson is on search and in addition to mentioning Elasticsearch (which I’ve heard of but not yet used) they discussed Solr (via Sunspot) which is completely new to me.

Much to learn!

I’m going through the (now free 🎉) Upcase course by Thoughtbot. In lesson 3 I just learned about rails db:migrate:redo to test rollback and migration in one go.

(On that particular exercise I still chose to run them separately so I could examine the DB in between though)

Listening to episode 10 of the Ruby Testing Podcast and Zach mentioned Page Object Model, a way to make integration tests more robust against minor interface changes.

Keen to investigate it more.

Update: A more Ruby focused link

Notify via Bugsnag When an Exception Hasn’t Been Raised

In a REST API I was writing, I wanted certain unlikely failures effecting customers to get logged to BugSnag as warnings so we would know if there was a pattern of failures, even if customers didn’t follow the instructions on the page to let us know.

From what I could tell reading the docs, BugSnag wanted me to pass it an error (exception) of some kind but these failures weren’t raising exceptions, they were just returning appropriate 4xx HTTP error codes.

There’s probably a better way of doing it but my eventual solution involved creating, but not raising, an error:

e = StandardError.new(‘Verified successfully but couldn’t fetch any records’)
Bugsnag.notify(e)

By the way, I would normally use a more descriptive variable name but I think this is one of those rare exceptions (pun not intended) where the meaning is so obvious and the variable is so short lived that it’s acceptable. A bit like using i and j as variables in a loop.

I tested this code from the production console to make sure it worked and that notifications came through to our internal chat app. What I noticed is that, perhaps because I didn’t raise the errors, the Bugsnags didn’t include helpful backtrace information like file names, line numbers or method names. The docs revealed a set_backtrace method and StackOverflow pointed me in the direction of [caller](https://ruby-doc.org/core-2.5.3/Kernel.html).

Of course I found myself using this same code 4 times in the same file, an obvious candidate to split into a method. Of those 4 times, they were split evenly between warnings and errors so the method needed to allow for that. I also wanted to be able to add a tab to Bugsnag with arbitrary information. Skipping to the finished product, the end result was:

  def notify_via_bugsnag(message:, severity: 'warning', aditional_info: {})
    e = RuntimeError.new message
    e.set_backtrace caller(2)
    Bugsnag.notify(e) do |report|
      report.severity = severity
      report.add_tab(:appname_API, additional_info) if additional_info.present?
    end
  end

The main thing to note is the addition of (2) to caller. Because I’m setting the backtrace from within a called method I want it to start one frame higher in the stack.

I then consumed this method in the controller with code like this:

      notify_via_bugsnag(message: 'Requestor was verified but student data wasn\'t saved',
        severity: 'error',
        additional_info: {
          student_id: params[:id],
        })
      head :unprocessable_entity

📚 I’m reading Seeing What Others Don’t by Gary Klein and came across this great quote:

The greatest obstacle to knowledge is not ignorance; it is the illusion of knowledge. — Daniel Boorstin

While I’m on the book theme, we listened to “Here Be Monsters” by Alan Snow (read by Bill Wallis) in the car as a family.

I’m a huge fan of borrowing audio books and ebooks from our local library on my phone using Bolinda BorrowBox. So convenient! 📚

These holidays I also re-read “Only Time Will Tell” by Jeffrey Archer (2013). It was a great read and I’m looking forward to reading the rest of the series (currently on reserve). 📚

Aforementioned (old but pretty good) book was “Inside Steve’s Brain (Expanded Edition)” by Leander Kahney (2009).

I don’t think it needed the “Lessons from Steve” at the end of each chapter but other than that I enjoyed it. It was well researched and well written 📚