Archive 2020


September 15, 2020

I’ve been building a system that imports a lot of records from another system. The items from the other system have stable identifiers, but many other attributes will change.

In the past I’ve handled this scenario by iterating on each record, and individually “upsetting” into the local database. It would look something like

entries = RemoteSystem.new.entries
entries.each do |entry|
  attributes = entry_attributes_from_remote_system(entry)
  Entry.find_or_initialize_by(identifier: attributes.fetch("identifier").update(attributes)
end

This works fine and good, but I learned there’s a better way! Rails 6 introduced upsert_all. With this new method, many round trips to the database are replaced with one command.

entries = RemoteSystem.new.entries
entries_attributes = entries.map { |entry| entry_attributes_from_remote_system(entry) }
Entry.upsert_all(entries_attributes, unique_by: %w[identifier])

The one gotcha I’ve found so far, is that it fails if entries_attributes is an empty array. Easily mitigated with a presence check.

Entry.upsert_all(entries_attributes, unique_by: %w[identifier]) unless entries_attributes.blank?

The Big Binary blog post has a lot of great information on usage.


September 9, 2020

I needed to rebuild some git history today. It’s never a fun task.

What I found while doing it, is that I was losing merge commits. I found this out to late, after taking a much less efficient approach. But if I ever encounter this problem in the future, the --keep-empty flag will be helpful. As in

git rebase -interactive --keep-empty upstream

September 4, 2020

My work habits really helped this week. What I’ve establish so far is:

  1. Process email at 9am
  2. Process requested code reviews in GitHub
  3. Process Trello
  4. Work from Things
  5. Process email after lunch
  6. Work from Things

I haven’t stuck to this rigidly. But when I do, the calm carries the day.


September 4, 2020

I built a Rails mailer for the first time in a very long time today. Revisiting the docs, I was greeted with a signature I didn’t recall from the past.

Mailer.with(some: "params", set: "this way").email_name.deliver_later

In the past, I’d always invoked mailers with

Mailer.email_name(some: "params", set: "this way").deliver_later

The with message feels very aligned with ActiveJob.set. For things that are needed on all mailers, like the recipient, I like standardizing on this approach for communicating params into the mailer.



August 31, 2020

Rails.env.test? is always preferable to writing Rails.env == "test". The behavior that powers this predicate method is the ActiveSupport::StringInquirer class.

This is not new information. But what was new, is finding the .inquiry method that is added to a whole bunch of objects, including strings and arrays..

"test".inquiry.test?
%w[this that other].inquiry.other?

Neat!





The Daily Motivator - Confident humility

August 27, 2020http://greatday.com/motivate/180516.html

Whatever you’re doing, a sense of superiority will make you worse at it. Humility, on the other hand, will make you better.

The moment you think you’ve got it all figured out, your progress stops. Instead, continue to advance and improve by reminding yourself how much more there will always be to discover.

Confidence is positive and empowering, but arrogance is deadly. Be confident, but not at the expense of your respect for others.

Don’t burn up all your energy proving how great you are. Invest your time and energy being thoughtful and helpful.

See the victories not as proof of your supremacy, but as opportunities to offer more value to life. See the defeats not as personal affronts, but as chances to learn and grow stronger.

Take care not to waste your time in delusions of grandeur. Embrace the power of confident humility, and live well.





Mavo

August 27, 2020https://mavo.io/

A new, approachable way to create Web applications

This is an extremely interesting idea. Make your site editable in place with a backing data store, and some markup.











A Ruby Macaroon Library

August 27, 2020https://github.com/localmed/ruby-macaroons

Macaroons, like cookies, are a form of bearer credential. Unlike opaque tokens, macaroons embed caveats that define specific authorization requirements for the target service, the service that issued the root macaroon and which is capable of verifying the integrity of macaroons it recieves.

If it means I can avoid JavaScript Web Tokens, I’m interested in exploring further.






August 27, 2020

We don’t have strongly formed or enforced language for the way we work. But I’d categorize this week as a cool down period. No heavy lifts on major projects. But a bunch of big wins on small bugfixes, code cleanups, and minor features that provide more context to the larger features that are already shipped.

Walking away in the afternoon is becoming a good habit. The commitment to abandon the currently pressing problems to focus on just walking is effective. The pressing problems become easier to grok when returning with fresh eyes.

School from home continues. Teaching my child about browser tabs, copy/paste, and turning-it-off-and-on again are an education in themselves.

Working from Things is an atrophied muscle. But I’ve made gains in the last two days that seem to be paying off. Getting a sufficient amount of tasks completed, with substantially less stress incurred.














August 26, 2020

The last 20’ish months have been spent building Planning Center Publishing. We launched into beta a few weeks ago, and have been able to release the gas pedal pretty significantly since then. I’m finally returning to a place of calm—it’s a welcome change of pace.

The events of the day were mostly shepherding Trello cards from left to right. I wrangled more than I anticipated, which is always a positive outcome.

School started today for the eldest child. From home, at that. It went smoother than we anticipated. During independent study, an overachiever emerged.

Proud dad.


August 26, 2020

Thanks to my partner in code, I learned that you can change the character that begins a comment in a Git commit message.

From the docs:

Commands such as commit and tag that let you edit messages consider a line that begins with this character commented, and removes them after the editor returns (default #).

If set to “auto”, git-commit would select a character that is not the beginning character of any line in existing commit messages.

I’m often writing Markdown in my commit messages, to leverage their legibility in other contexts. Before this configuration, headings were off limits. Now that I’ve changed my configuration with git config --global core.commandChar ";", they’re gonna be all over the place.


June 27, 2020

A byte order mark is an optional character that may appear at the beginning of a text stream. The unicode character U+FEFF can be used to signal several things to a program reading the text.

My program reading the text is Ruby’s JSON.parse. The text being read a JSON payload from the Pinboard API.

A helpful email exchange with Pinboard support is what pointed me in the right direction. A recent server upgrade began inserting the byte order mark where it wasn’t present before. It sounds like this insertion is going to be removed, because it makes the raw JSON payloads un-parsable by JSON.parse in both Ruby and JavaScript.

In the meantime, I wanted to get my parsing fixed, so I could keep my Pinboard powered links up-to-date. With the tip from Pinboard support and some StackOverflow I got my JSON parsing fixed.

  def load_remote_json
    uri = URI("https://api.pinboard.in/v1/posts/all?tag=danott.co&format=json&auth_token=#{auth_token}")
    body = Net::HTTP.get(uri)
+   body = strip_byte_order_mark(body)
    JSON.parse(body)
  end

+ def strip_byte_order_mark(potentially_unparsable)
+   potentially_unparsable.dup.sub("\xEF\xBB\xBF".force_encoding("UTF-8"), "")
+ end

This experience highlighted the tradeoffs of using vcr for tests. On the positive side, I had a cassette recording that captured the old API response. This allowed me to diff the old response and the new response to dig down and find what changed. On the negative side, I didn’t encounter the failure in parsing until it broke my link importing in production.

Tradeoffs.




Deku Deals

May 22, 2020https://www.dekudeals.com/

Nintendo Switch price tracking and wishlist notifications

I started building something like this on AWS when I wanted to wait for Celeste to go back on sale. I’m so happy somebody else did it and I can delete those stale resources.





































January 13, 2020

Needing to reduce a pathname into the filename without it’s extension is something I need to do often. But not too often. Just often enough to forget how I last did it, and clobber together a solution anew.

So this time I’m writing down the briefest solution I’ve found in Ruby, in hopes that it’ll commit to my memory.

require "pathname"
pathname = Pathname.new("~/some/path/to/the/mountains.jpg")
pathname.basename(pathname.extname).to_s # => "mountains"

Pathname is a great tool in the standard library.




January 7, 2020

Sometimes you install one gem.

gem install bundler

Sometimes you install it with a specific version.

gem install bundler -v "2.0.2"

Sometimes you install multiple gems.

gem install bundler minitest

But what do you do if you need to install multiple gems with specific versions? It is possible with a special syntax!

gem install "bundler:2.0.2" "minitest:5.13.0"


January 6, 2020

Something I really like from React Native is the global variable __DEV__. Being able to do things only in the development environment is quite handy. This concept is not unique to React Native, but that’s where I was introduced to it.

I’ve found myself in need of a similar strategy while building this static site in Rails. I have some dynamic interactions that I can use to curate content on my own machine, but I don’t want those scripts bloating the static build that is deployed to production.

This can be achived in Rails with webpacker using Webpack’s DefinePlugin!

// config/webpacker/environment.js
const { environment } = require("@rails/webpacker")
const webpack = require("webpack")

environment.plugins.prepend(
  "Define",
  new webpack.DefinePlugin({
    STATIC: process.env.NODE_ENV === "production",
  }),
)

module.exports = environment