Building a Flexible Table Component with Vue JS

If you’ve known me or worked with me for any length of time, it’s no secret that I’m a big fan of Vue.js. While I’ve had a little more experience now working with React, I still find myself coming back to Vue because of the robust 1st party ecosystem, plug-n-play modularity, and defacto organization of components. Single File Components (SFC) are amazing! But that’s not what we’re here to chat about today. Today we’re talking about something no one likes; tables.

Note, this tutorial should be relevant to both Vue 2 and Vue 3. The syntax for slots was unified in the later years of Vue 2 to better match what was coming in v3.

If you’ve ever had to build a table component of any complexity with a JS framework, you know it can be very tricky to nail the abstraction. Do I need sorting? Should the rows be striped? How can I customize specific cells? What sort of things should I expose as props? These are all important questions that you’ll eventually ask yourself while working on any project with a usage life of more than a few months.

Let me first start by saying this; if your app/site only needs 1 table with static data, don’t make things complicated. Write it inline or maybe extract it to a new component just to not clutter up your page component with a lot of static data. I would even go so far as to say, if you need a lot of complicated features (like sorting) but it’s all confined to this one table, to build it all in one file, or perhaps break it up for legibility. The logic though should remain in the main file however.

Where a reusable table component becomes useful, is when you actually need to reuse it! So often I’ll see someone fretting over an abstraction and wasting time for something that doesn’t matter. If it’s only used once, it’s not worth abstracting.

At work, we’ve began building out some new pages to go alongside a new redesign. As part of this effort, we’re creating various components for bits of UI that are used throughout the new designs and layouts. Normal stuff, buttons, inputs, cards with shadows, etc. Two weeks ago, I was given free reign to build out a brand new feature within our app. This feature was largely build around a few very similarly styled tables, but each one featuring a small bit of custom functionality. In one table, the data was sortable, while in another, we needed checkboxes in each row to multi-select various rows and process them for some bulk action.

When I started the build, I did it all statically. I built the entire feature in the first week of our sprint with zero abstractions. I started with the simplest table, a few columns with static content and no special features. Then I moved on to a more complicated table, copy and pasting the first as the basis for my next iteration. By the time I got to table number 4, I was seeing some concrete patterns emerge about how the CSS needed to change to accommodate each of the unique workflows.

I feel like a broken record, but this is why I think it’s so important to not abstract too early, even if you know that you’re about to build 5 of the same thing. When you have a lot of duplicated examples to compare to each other, the real patterns stand out so clearly. I know from experience that attempting to discern the abstraction before you’ve even made a first pass rarely turns out well. A great abstraction will lend itself to a quick refactor, so don’t be afraid to “waste time” earlier in the process, so you can fly across the finish line at the end!

Now, I’ll be the first to admit that I also did some searching online to see how other people approach this. Unfortunately, a lot of articles around building tables with JS frameworks tend to focus on flashy, feature filled monstrosities that attempt to compete with the Bootstrap tables of yore. I didn’t want that. Eventually, I stumbled across a Medium article outlining an interesting take on using dynamically named slots to expose various parts of the table to the consuming component.

Before I show you the code, let me try to explain. Imagine you have a table with a 3 columns, an ID, a name, and an email address. Since we’re using a table, one fairly consistent feature is the stability of the visible columns. Imagine we assigned each of these columns a key, say id, name, and email. Now, for each row, we know we will need to populate each of those columns with some data. Normally, we do this by associating data from the row with a column. Here’ what an example row might look like.

  id: 123,
  name: 'Mr. Potato Head',
  email: ''

Makes sense right? We build out the table by first looping the rows, and then looping the columns, and for each column’s key, display the appropriate data from the row. Standard stuff for building a table.

So let’s take this one step further. When we loop over each column within a row, let’s add a slot around the cell’s content, using the column’s key as the unique identifier.

<slot :name="`cell(name)`">
    {{ }}

I’ve simplified this quite a bit from the final form, but hopefully you can see where we’re going! To override every name cell for our table component, we only need to provide a slot targeted at cell(name). We would do that using <template v-slot:cell(name)> or the shorthand <template #cell(name)>.

This simple abstraction allows us to target a certain bit of the table with extreme precision, using a very readable syntax. With scoped slot properties, we can even make more granular decisions within our slot template if one cell in particular needs even more special treatment. Pretty cool huh?

Now let’s take it another step further. What if we added a slot for not only each cell, but also each row? Assuming our row has some sort of unique identifier, like an id or key property of it’s own, we can also target those dynamically!

<slot :name="`row(${getKey(row)})`">
    <!-- the slots for cells are nested here within the row -->

We’re adding a little complexity here but it’s still manageable. The name of the row slot is going to be equal to row(KEY_OF_THE_ROW_DATA). In my case, I’m using a helper function to try and guess a unique key, but you could also defer to something like an id property if that is always present on your row data.

What makes this cool, is that we can then override just one row as long as we know the unique identifier!

<template v-slot:row(12)>
    <td colspan="3">This is the row with an ID of 12!</td>

With this abstraction, you can now override just a single row within the table if necessary, without adding extra complexity for other rows that may not need to be rendered differently. Now let’s go ahead and see the full example!

const BaseTable = {
    props: {
        fields: {
            type: Array,
            default: [],
            validator(fields) {
                return fields.find(field => field?.key === undefined || field?.label === undefined) === undefined
        rows: {
            type: Array,
            default: [],
        emptyMessage: {
            type: String,
            default: 'No rows found.',
        tableClass: {
            default: 'm-0 table-fixed overflow-hidden rounded-lg',
        headClass: {
            default: 'bg-gray-200',
        headRowClass: {
            default: 'uppercase',
        headCellClass: {
            default: 'p-2 text-xs font-bold text-gray-800',
        rowClass: {
            default: '',
        cellClass: {
            default: 'p-2',
    methods: {
        getKey(row) {
            return (row?.key || row?.id) ?? JSON.stringify(row)
    computed: {
        visibleFieldKeys() {
            return Object.entries(this.fields).map(([_key, value]) => value.key)

export default BaseTable

    <table :class="tableClass">
        <slot name="thead" :css="headClass">
            <thead :class="headClass">
                <slot name="headRow" :css="headRowClass">
                    <tr :class="headRowClass">
                        <template v-for="field in fields">
                            <slot :name="`head(${field.key})`" :field="field" :value="field.label" :css="headCellClass">
                                <th :key="field.key" :class="field.class || headCellClass">
                                    {{ field.label }}
        <tbody v-if="rows.length">
            <template v-for="row in rows">
                <slot :name="`row(${getKey(row)})`" :row="row" :css="rowClass">
                    <tr :key="getKey(row)" :class="rowClass">
                        <template v-for="objectKey in visibleFieldKeys">
                            <slot :name="`cell(${objectKey})`" :value="row[objectKey]" :row="row" :css="cellClass">
                                <td :class="cellClass" :key="objectKey">
                                    {{ row[objectKey] }}
        <tbody v-else>
            <slot name="no-data-row">
                <tr :class="rowClass">
                    <slot name="no-data-cell">
                        <td :colspan="fields.length" :class="cellClass">{{ emptyMessage }}</td>

Wen you combine all the potential options for where to insert a slot, this pattern becomes extremely flexible without creating a ton of overhead.

Say I wanted to make the table sortable by name. Since the table is driven by data loaded from somewhere else, we essentially only need to add a button to the top of the name column that can fire the method to sort our underlying table data. Let’s see how we might implement that.

  <template #head(name)="{ css, value }">
    <th :class="[css]">
      <div class="flex items-center justify-between">
        <div>{{ value }}</div>
        <button aria-label="sort" @click="sortByName">👇️</button>

How easy was that?!?! We haven’t had to dig into the table to hook in a bunch of events, we don’t need a bunch of callbacks; everything we need is in scope the component controlling the table’s data. The BaseTable component purely exists to display the data. Each slot also exposes the original CSS for the element so we can choose to maintain the same styling, or we’re free to ignore it and roll our own for that cell/row. We also pass back props of the original value for the cell and optionally we can include the full row of data if we need that to make other decisions.

What’s also great about this is that it’s easy to extend into other abstractions if you find yourself using the same patterns over and over again. Your BaseTable component can stay very simple while more specialized components can emerge for often reused patterns, eg. SortableTable or SelectableTable.

Hopefully this gives you a good idea as to how you may create a table component for your project. If you happen to implement something similar to this in your project, I’d love to see it! Tag me in a tweet @daronspence showing off your work! I’m always really interested to see how folks are utilizing these very low level components within their applications. I can’t wait to see your take on tables!

Adding Vue Devtools Support to Safari with Laravel

When developing applications with VueJS, the devtools are an excellent resource for debugging and development. For Chrome and Firefox, an official extension is available that adds support directly within each browser’s own devtools suite. Safari however, does not share the same extension model and therefor some workarounds are required to use the devtools with Apple’s browser.

In this tutorial, I’ll show you how to add support for Vue devtools in Safari within the context of a Laravel application.

Install Vue Devtools

First, you’ll need to install the Vue devtools locally. You can reference their documentation, but I recommend installing them globally with npm.

npm install -g vue-devtools

To start the devtools application and server, you can run vue-devtools in your terminal.

Note: You will need to run the `vue-devtools` command each time you want to start a debugging session.

Once the devtools are running, you should see a mostly blank screen like this.

The Vue Devtools Splash Screen

Custom Laravel Blade Directive

Here is where the magic happens. We’re going to add a custom blade directive that will inject the required script tag wherever we request it. A little logic will allow us to dynamically check the user agent and then output the script tag for the Safari browser.

<?php // within your AppServiceProvider::boot method.

Blade::directive('vuedevtools', function ($expression) {
	return <<<PHP
		if (
				app()->environment() === 'local' 
				&& ((bool) ! \Str::of(request()->headers->get('user-agent'))->contains('Chrome'))
			|| env('USE_EXTERNAL_VUE_DEVTOOLS', false)
		) {
			echo '<script src="http://localhost:8098"></script>';

Let’s go line by line and I’ll explain what is going on.

First, we register the directive with the static directive method on the Blade facade. Next we have a little trickery! Due to how template caching works, we need to evaluate these parameters within a PHP tag that is output in place of the directive.

To facilitate legibility, I’m using a heredoc to write the returned string.

Within the heredoc, we’ll first check if the app environment is equal to the string local. You can set this with the APP_ENV variable in your projects .env file. Next, using the Str facade and fluent strings, we will evaluate if the incoming request’s user agent includes the word Chrome. Due to historical norms, most web browser requests made on a Mac will include the word Safari somewhere in the User Agent. The Chrome user agent also includes its own name, so we can check for its existence. I haven’t tested this with Firefox, but if you’re seeing the extra script tag in that browser and you don’t want it, you should be able to clone this line and check for Firefox as well.

Finally, we’ll check for the existence of a USE_EXTERNAL_VUE_DEVTOOLS environment variable. Setting this to true will always render the script tag necessary for the standalone Vue devtools application to function, regardless of the browser being used.

If all of those variables evaluate to true, the app env is local, and we are not using Chrome, we’ll echo the script tag linking to the Vue devtools.

To make everything work, the last step is to include the @vuedevtools directive somewhere within your application’s main view file. This can be a Blade layout or component. Just know the script tag will be output in that location.


With this information, you should have data in Vue Devtools from your application. If you’d like to evaluate less code in your production environment, you can also wrap the directive in an environment check within your application’s layout file.


If you have any questions, feel free to ping me on Twitter!

The utility of unhappiness

To many of you likely reading this article, it’s no secret that I’ve struggled with my weight over the past few years. I had a pretty good push forward in terms of my health in 2019 and since the start of 2020, it’s been mostly downhill. Today I’m writing some thoughts down about some recent ideas that have been floating in my head.

A big part of my every day is a search to maximize happiness. Very few things I do, are a result of a feeling of obligation. My job is probably the only thing that I do out of obligation currently. It’s not all bad though; working enables an income which enables all of the other things that I like to do that happen to cost some amount of money. If presented with an opportunity to maintain my current lifestyle, but without work, I would absolutely take that and at least try it out for a few years. I think I’ve read enough accounts about people floundering in retirement to push me off turning into a couch potato more than I already am. I think I would find something to do.

Back to the topic; basically all I do is because I those things make me happy. Some primary examples are as follows: I eat the foods I want because they taste especially good. I watch movies or read books that I find interesting/fun. When I engage in a particular hobby, it’s because doing that thing makes me happy in that moment. I passively engage in the shit-show that is online politics because I think it’s fun!

Some secondary examples may include some activities that aren’t “fun” per se, but I can enjoy them most of the time. Most of the things I do for my wife probably fall into this category. I want to see her happy, so I do certain things to increase her happiness, which makes me happy! I don’t think that sort of quid pro quo is bad; just a reality of life that I prefer to make the most of. I want to emphasize the difference between these and work. I don’t do them out of obligation in the traditional sense. I have a job because I am essentially forced by society to have one. I do chores because the utility of those actions creates happiness for another person that in turn creates a cyclical ingress of serotonin between us. A benefit is those chores usually make me feel better about my place in my life after they are completed.

Another secondary thing is personal hygiene. Because I work from home, it can be pretty easy to go a little longer than most people without taking a shower. I’ve tried to pinpoint where that changed, because I grew up as a kid taking a shower basically every day. Somewhere between the end of high school and the year I started college, that habit got broken and it’s been really hard to start it back up again. I never feel bad about it, but because I never seem to have a desire to jump in the shower, it can fall behind other things. Brushing my teeth is another example. Though, I was always terrible at that as a kid too. For my wife’s sake, I’m trying to get better at brushing, and her pressure (or usually outright refusal to engage) is enough to nudge me in the right direction. I appreciate the nudge and every time I get that reminder, I’m a bit embarrassed. Hygiene is something I never feel bad about (and sometimes feel great afterwards!) but that memory doesn’t seem to be sticky enough to form some neural pathway into my permanent habits.

Maybe that’s what it is? Things I like to do, are habits more or less?

Habits that have changed that I can remember in the past few years: Brushing my hair. Used to not do that one but once a week or so, but I think I was physically pained enough by those experiences that I decided it was worth doing more often. Similarly, the way I shampoo my hair changed after getting married literally overnight. Ladies, imagine washing your hair by lathering everything together into a giant ball of madness. Running your hands back and forth over each other, creating a massive knot of (clean) hair, and then you need to spend 30+ minutes brushing the chaos out. That was me for 4 or 5 years.

I feel like some car maintenance habits might fit into this category. I engage the parking brake whenever the engine stops because in theory it saves my transmission some wear from holding the vehicle stationary in park. I never cared about oil changes until I almost blew an engine up. My parents never told me that oil could burn up really fast on older cars!

Some patterns I’m noticing as I write these out. If something is going to cause me pain (physically or mentally), I’m just as likely to change my behavior in response to that negative stimulus. Sometimes that negative stimulus is monetary, like with the car stuff, or actual physical pain in the hair examples. I think the issue here though, is that there are some things that I want to make habits of, that I can’t seem to get through because it’s not fun/painful enough.

Back to the chore example. I’m not perfect in doing all my chores every day, but nothing gets me off my ass faster than the knowledge of people coming over to make me tidy up. Since we’ve moved into this new apartment in Jan 2020, I think the apartment has not been “clean” for perhaps 5 (or less) visits by outside parties. Even then, only one of those that I can remember wasn’t immediate family. The mere thought that my own parents could think I am a slob living in filth is plenty to kick me into gear and tidy up (at least a little). Meanwhile, I go to their house all the time with 5 kids at home which is a train-wreck 50% of the time. I have a feeling there wouldn’t be any judgement!

Just yesterday, I got an email that fire code inspections were happening and as soon as I read that email, I got up and picked up all the trash laying around from dinner the night before (take-out containers and empty cans). I’ve seen my next door neighbor’s apartment. The inspectors would be overjoyed at the “cleanliness” of my unit compared to theirs.

So to the title of this article, “The utility of unhappiness”. This idea has sat with my over the past few days. It was sitting with me as I shopped for groceries a few short hours ago. What if I made a conscious effort to recognize my unhappiness in some action, and confront that uncomfortable feeling? Maybe once a day, I ask myself, “what is something you’ve done that doesn’t make you happy right now, or in the near future?”

I actually have some ideas to send this to a few people and ask them to prompt me. And I say a few because I know they’re human too and new habits are hard. Then I can at least get some friendly interaction as well as check-in on my progress. Side-note: I wish reminder apps worked for me. Again, it goes back to the pain/pleasure thing. It’s not painful enough to ignore, so eventually I do just that!

Wrapping up this ramble-fest, the shopping trip today was somewhat influenced by these thoughts. I bought good food instead of 120 pizza rolls and 3 bags of chips and dip. I’ve not gone back for seconds on my healthy dinner yet in favor of writing this post; giving the food time to settle so I hopefully feel more full. I’m committed to taking a shower and brushing my teeth later this evening. I didn’t want to do these things. I’d rather watch some tv and veg out after a long day staring at this fucking screen.

Unhappiness in my mind is somewhat of a morally loaded term, but maybe it doesn’t have to be? Maybe it can be more of a neutral state, or a transition to something good? Changing that framing though is another exercise in habit building that I’ll have to struggle with in the meantime.

If you happen to be reading this and got way down here, thanks! I appreciate it. If you want to provide some accountability, please feel free to text me or send a Twitter DM asking, “How have you engaged with unhappiness today?”

If I don’t respond promptly, I likely read it and forgot to come back and respond due to “busy-ness”.

I appreciate any and all feedback you may have and if you’re struggling with similar feelings, maybe we can help each other out? One more thing to try to think about and engage with… 😉

Serving Requests without Sessions in Laravel using Inertia.js

This article serves as an addendum to the excellent article by Chris Fidao over on Laravel News.

When using Inertia, you may still want to serve some content without generating a session for an anonymous user.

# app/Http/Kernel.php
'static' => [

However, if your Inertia middleware relies on any session data, stuff could blow up!

Session store not set on request error

A quick fix is to return early in the share method of your HandleInertiaRequests middleware.

public function share(Request $request)
    if (!$request->hasSession()) {
        return [];
    // ... do the rest of your sharing stuff here.

That’s it! Happy developing!

Installing and using Xdebug with Homebrew, Valet, and VS Code in 2021

As I was working on a client project, I needed to do some more in depth debugging in a PHP application. Laravel has a couple of great utilities like dd() and dump() that make the output of something like var_dump() much more readable and actionable, but sometimes it’s not enough. There’s another tool that came from the Laravel ecosystem called Ray that’s also worth checking out. It’s kinda like dump() on steroids and well worth the money in my opinion. However, the king of all debugging tools for PHP is still hands down Xdebug.

Getting Started

Before diving in, it’s important that we’re all starting from the same place in regards to tools.

  • You’ve installed and configured Laravel Valet and it is serving sites from somewhere on your local machine.
  • You’re using Homebrew in conjunction w/ Valet to manage PHP versions (default for Valet)
  • You have installed the excellent PHP Monitor utility application.
  • You have installed the Xdebug Helper Chrome Extension
  • You have installed VS Code
  • You have installed the PHP Debug extension for VS Code

Installing Xdebug

Xdebug version 3 was released in late 2020 and configuring it has become much simpler assuming you are using the defaults. The documentation on the Xdebug website will work for a lot of folks, but if you use multiple PHP versions via Homebrew, sometimes the tools can get confused when installing.

First, we need to find the real path of your PHP installation. On the command line run this command:

brew info php # default php version, 8.0 at the time of writing
# or 
brew info php@7.4 # or php@7.3 etc

This will spit out a bunch of stuff you can ignore for the most part, but we want this line:


Your installation path might look different depending on your PHP version or Homebrew configuration. The important thing is that we want to go into this folder and utilize the utilities within it to install extensions using the pecl utility. By using this path, when we run pecl, it will know the correct location to find and modify configuration files.

Next, we’ll install Xdebug via PECL

/usr/local/Cellar/php/8.0.3/bin/pecl install xdebug

This will take a minute or two depending on your machine and internet connection. When it’s finished you should see this output somewhere near the bottom of your terminal.

install ok: channel://
Extension xdebug enabled in php.ini

If you see these lines, congratulations, you’ve successfully installed Xdebug!

Now, we need to configure one more thing. By default, Xdebug starts in develop mode which isn’t super useful. It enhances the default error screens and var_dump() output with better formatting and stacktraces, but doesn’t enable us to do step-through debugging.

Run the below command to find your php.ini location.

php --ini

This will show you all of the configuration files currently being used by PHP. By default, the Xdebug configuration is added to php.ini. Open that file in your favorite text editor. Mine was located at /usr/local/etc/php/7.4/php.ini

At the top of that file, just below the zend_extension="" line, add xdebug.mode="debug"

This tells Xdebug to start in debug mode, for, well, debugging!

While you’re on the command line, go ahead and run pecl install redis if you work on projects that utilize Redis. The PHP extension is much faster than the predis/predis Composer package.

You can restart Valet with the following command and then use PHP Monitor to confirm Xdebug is installed. You must restart PHP for new extensions to be enabled.

valet restart
PHP Monitor Settings

You can also verify Xdebug is installed by running php -v in your terminal and verifying the with Xdebug v3.0.4, line is included in the output or by running the phpinfo() function and searching for Xdebug information in the output.

Configuring VS Code for Debugging

Before we begin configuring VS Code, we need to tell communicate with Xdebug that we would like it to operate in incoming web requests. Navigate to one of your PHP projects in the browser, and enable the Xdebug helper Chrome Extension for that site.

You may need to click on the Puzzle Piece icon in Chrome to show all of your installed extensions.

This debug setting appends a Cookie to every request made from this URL that is specific to Xdebug. When Xdebug sees this Cookie, it knows to prepare itself for a debugging session. This allows us to essentially bypass Xdebug when we don’t need it so our web requests are still lightning fast. I believe this is a new feature (or at least exposed more directly) with version 3.

You can verify the Cookie is being sent by inspecting requests from the site in Devtools. The XDEBUG_SESSION cookie is the magic sauce! 🔥

Now that our browser is sending the correct Cookies and Xdebug is installed, we can configure VS Code to listen for incoming debugging sessions. This is an important thing to understand. When debugging is enabled, Xdebug initiates the connection to your IDE, not the other way around. We must configure VS Code to respond the location Xdebug expects (or change Xdebug to connect to different ports/hosts). We’ll be sticking with the defaults for this tutorial because it’s easier.

Open your project in VS Code and enable the PHP Debug extension I referenced earlier. Open the debug tab in VS Code and click the gear icon near the top of your sidebar.

This will generate a launch.json file for you in the .vscode directory at the root of your project. You can choose to commit this to version control or not, though I generally would not recommend it since Xdebug configurations may be different across your team.

The only thing we need to change in this file is the port that VS Code is responding on. The correct port for a default install of Xdebug is 9003. You can change it for both blocks in the config file.

After this, I generally find it worthwhile to completely restart VS Code. After restarting, open the Debug tab in VS Code again and click the green arrow to “Listen for Xdebug”.

We can now add a breakpoint by clicking the red dot to the left of any line of PHP code. I recommend adding it to a variable or first line of a function.

The default public/index.php file of a Laravel Project.

Now, open your browser, hit refresh, and hopefully VS Code will automatically focus on your breakpoint! You can disable VS Code breaking for “Everything” by unchecking the relevant box in the “Breakpoints” section of the debug sidebar.


Hopefully this has been helpful to you to enable Xdebug while using Valet on a Mac. If you have any questions, feel free to reach out to me on Twitter! If you want to add something that I may have missed, reach out and I will update the post and give you credit.

PHPUnit and Laravel Config Caching

This week at work, I ran into a fun issue with a colleague while running some unit tests that I wanted to document here.

I was writing some new unit tests for a legacy codebase that’s been around a long time. For the sake of portability, I decided to use an in-memory SQLite database. After writing the tests and finishing the other work for the ticket, I opened a PR and went about my other tasks.

My colleague pulled down my ticket for testing and ran the tests. What should have been a very simple test was failing! What was weirder, is that the failing action was happening during one of the database migrations. The error isn’t important but for the sake of completeness, but it was a foreign key constraint error on the database.

After trying to debug stuff with them, we also noticed that his local database had been entirely nuked. Considering the test was running with the RefreshDatabase trait, I was starting to get an idea of what was going wrong.

What happened?

The empty database was the big clue that led me down the rabbit hole. I knew that running the database migrations is a slightly different process for in-memory vs. a real database, so I dug into that trait first.

This method in the call stack stuck out to me:

protected function usingInMemoryDatabase()
	return config('database.connections')[
	]['database'] == ':memory:';

If the config value is for the default database is :memory: then this would return true. Since PHPUnit overrides your .env when the tests are ran, this should be the correct value. Dumping it however, we get a different result.

For the config() function to be returning a different result than what is in a configuration file already, that must mean a config cache file exists. You can read more about how Laravel potentially includes that file here.

In our case, there was a config cache present, so when Laravel was booting to run the tests, that config was being used instead of PHPUnit’s environment variables.

To tie it back to the error we were seeing, since the local MySQL database was being used instead of the in-memory database, a migration with some outdated seeding code was throwing the foreign key constraint error. This is also a good reminder that MySQL and SQLite are not the same! If you are expecting foreign key constraint failures to be enforced in your tests, use the appropriate database for both your test suite, and when running your application.

The Solution

If this case, I decided it was best to try and fix the problem for the user running the tests. I modified the base TestCase.php as follows.


namespace Tests;

use Illuminate\Support\Facades\Hash;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
     * Creates the application.
     * @return \Illuminate\Foundation\Application
    public function createApplication()
        $app = require __DIR__ . '/../bootstrap/app.php';



        $this->clearCache($app); // Added this line.

        return $app;

    protected function clearCache(Application $app)
        // We don't have a cached config, so continue running the test suite.
        if (!$app->configurationIsCached()) {

        $commands = ['clear-compiled', 'cache:clear', 'view:clear', 'config:clear', 'route:clear'];
        foreach ($commands as $command) {
        // Since the config is already loaded in memory at this point, 
        // we need to bail so refresh migrations are not ran on our
        // local database.
        throw new \Exception('Your configuration values were cached and have now been cleared. Please rerun the test suite.');

If no config cache file is found, then we’re golden! Continue running the test suite. If we do find a config file, we run a few Artisan commands to clear all of those files and then throw an Exception. The exception is necessary since the config is already loaded into memory at this point. If the tests continued to run, all of the requested config values would be the old ones. While it may be possible to reset the config and continue running the tests, the utility of that is miniscule. Instead, we inform the user of the action that was taken and ask them to run the test suite again.

In an ideal world, you would never have a configuration cached locally as it’s main purpose is to speed up expensive disk operations in production, but alas, we don’t live in an ideal world! 😅

I want to give a shoutout to Joel Clermont for helping me debug what was going on and being a great rubber 🦆!

How to forward catch-all email after canceling Google Apps subscription

I am doing some digital house cleaning and I’ve wanted to cancel a Google apps business account for a while now but the ease of using the catch all domain names has been great and I didn’t want to give that up. Plus the interface for Gmail isn’t that bad.

I know there are paid services out there that offer similar functionality and I was ready to buy one until I came across this!

Enter 🎉

It’s an open source and free email forwarding service that can handle catch all addresses. Setup is simple. Add some MX records, then add a TXT record with a forwarding address. This does make your forwarding address public but since I use Hey I have pretty good control on who is allowed to email me thanks to The Screener.

Just in case, I did change the few accounts still using those custom domains, but I’ve tested it and so far within about 20 minutes things seem to be propagating nicely. I’ll be keeping an eye on it over the next few weeks but an hour in and I’m pretty happy!

Check it out!

Health update – March 2021

Been a hot minute since my last update! To those of you that reached out to check on my progress, I am very appreciative and touched that you take the time out of your day to think of me. It’s encouraging to my soul. ♥️

Since my last update in January, things have been pretty a-ok. I’ve been seeing a therapist since that time and while I don’t feel that I’ve come to any sort of dazzling revelation, I keep scheduling appointments at the end of every session. I think part of what I’m latching onto is the accountability of talking to someone. I pay this person $100+ a month to listen to me give progress reports of my mood and feelings, and my physical health obviously plays a big role in that. Maybe I would do just as well with one of those gambling apps where you put down some money to accomplish some task and if you fail, they don’t give it back?


My Apple Fitness workout history

As you can see from the picture here, I’ve gotten into working out a little since the end last week of January. 95% of the time, this is riding the stationary bike in my building’s gym, but sometimes I’ll go for a long walk up and down the parking garages’ surrounding my house (it’s been cold though!). It’s light exercise by any standard; very low impact, and I usually stop soon after my exercise ring closes; about 30 minutes. In that time, the bike says I travelled 6-8 miles, depending on my pace.

The biggest break was the week of February 15, where Texas had the snow-pocalypse that cut power to millions of people and dozens died of exposure, indoors. While I won’t go into the politics of it all, needless to say that week was weird. My partner and I went to my parents house on Monday night and were there most of the week. My parents don’t have a gym and I didn’t want to go trek in the snow just for a workout so I stayed inside.

I can’t say that the workouts are providing a lot of physical benefit. My weight hasn’t dropped drastically (as will be evident soon) but I cannot definitely say there is no benefit at all. This past week I’ve been working out later in the evening, around 10-11pm, and largely have been motivated to that thanks to the support from some colleagues at work. A few of us have Apple Watches and getting the notification that someone closed all of their rings for the day is a surprisingly effective motivator. The fact that I am responding to that pressure in a positive way is probably a good thing. I can easily think of times past when I would have laughed at those notifications and went back to watching TV and eating an entire bag of Doritos (…now I want Doritos…).

As the weather begins to warm up here in Texas, I want to try taking my rides outdoors as I have acquired an actual bicycle from a friend. I’m interested to see how that goes over the next few months.


My diet has been generally the same as before and I’ve done a decent job of sticking to my targeted macros. In the past two weeks, I’ve fallen back into my Wingstop habit, which is not sustainable calorically or financially, but the dopamine hit has been undeniable at times.

My go-to dinner has become a large salad with 4-5oz of greens, an ounce or two of goat cheese, fresh strawberries, and a handful of nuts with some sort of low carb dressing. I pair that with some protein, usually chicken of some variety, about 6-10 oz if I had to guess. Chicken thighs are my favorite though.

When I do get Wingstop, I’ve now transitioned to only ordering chicken (without my usual large side of fries). That alone is a reduction of close to 1000 calories and 100 carbs when y0u factor in the ranch dipping sauce. If I have the ingredients available at home, I will first make a salad like I described above, eat that, then eat the wings. The greens soak up a lot of the grease and upsets my stomach less, while also helping me feel fuller. I noticed this last night as I finished eating around 8:30pm and didn’t feel compelled to eat more the rest of the night.

At 10pm, I noticed the time and thought I wanted to get a snack, but managed to talk myself into drinking a big glass of water instead. My usual after dinner snack can be 500-800 calories of roasted nuts so great calorie savings there.

I still have a weakness for snacks, which I tend to eat after dinner but I think I’m doing better. For instance, I’ve started eating fresh strawberries as a snack which is surprisingly less bad than I originally thought. A pound contains 150 calories and 22g of carbs with about 8g of fiber. Those aren’t keto macros, but I can often feel stuffed after finishing a container. Satiety is my biggest goal when eating so that’s fine by me.

I’m still taken with how my tastebuds have changed in reaction to my decreased sugar intake. The strawberries now taste so sweet to me, it makes one part of my brain think that there’s no way they’re healthy, but they are! A few weeks ago I got a craving for a shake from a fast-food joint and it was insanely sweet. I still drank it, but I honestly haven’t had the craving since and writing about it now, I am unfazed.

If I had to rate my diet since the last entry to this series, I’d probably give it a solid 7/10. Not perfect, but not a total failure either. C+

Weight Loss

The graph tells most of the story, but I’ll elaborate. I’m not sure if I put numbers out there, but then end of 2020 was rough. As you can see, I gained 20 pounds in about 2-3 months, despite intermittent fasting 16+ hours a day during that entire time.

Since January, I’ve been back to my 5 meals a week eating schedule and making progress in a positive direction. At the end of January, I purchased a new bathroom scale which has been encouraging and like I mentioned earlier, I’m now also working out every day. My body fat percentage has decreased by about 4% in that time, which feels good to me. I’m currently just under 38% body fat, which is still a lot, but it’s miles better than the high 40s I was rocking in 2018.

February was basically flat in terms of weight loss for the entire month, with some ups around when the storm hit. Considering one night that week I ate an entire large pizza by myself, probably not the worst outcome! March has been better, though we’re only 6 days in.

Tonight is my dad’s birthday and we’re going to an all-you-can-eat steakhouse and I’ve already resigned myself to indulging on some mashed potatoes and likely a full pound of meat, but honestly, it’s probably not that big of a deal. This month, I’d like to try and focus on mindfulness when it comes to snacking as that’s where I believe the bulk of my hindering calories come from. The roasted nuts especially.

If I can get under 250 by the end of the month without immediately fluctuating above that number in April, I’ll be really happy I think. That’s 1 pound a week which should be totally doable and sustainable. If I can keep that up for a year, I’ll be entering 1-derland in time for Summer 2022. That’s exciting!

I think I mentioned this before but I’ll say it again because I’m thinking about it. Winter 2020 was huge bummer for me because I had done so well in 2019. I bought new clothes that I was excited to wear, especially the following winter, that I ended up not being able to wear comfortably at all without risking damaging them. That fucking sucked. If I have one goal for 2021, it’s to be able to wear my new coat comfortably all through next winter. No bulging buttons or getting too hot that I need to take it off after less than 5 minutes indoors.

Final Thoughts

Thank you to everyone who has supported me over the past few months. Thank you to my wife who doesn’t complain when I suggest Wingstop every time a discussion about dinner comes up. Thank you to my parents have been supportive of my lifestyle changes and don’t pressure me to eat when I don’t want to. I know there are a lot of people out there who have differing views on fasting for weight loss, and my thoughts are with them as we all navigate this rocky journey to better health together.

If you want to chat about how your life is going, food related or not, hit me up on Twitter. My DMs are open. Talkin’ to new people online is really fun for me and I’ve been told I’m an excellent sounding board.


Photo by Dovile Ramoskaite on Unsplash

Installing Laravel Spark Manually with Composer – 2021

For whatever reason, you may need to install the new Laravel Spark into your project without following their installation instructions. Sometimes you don’t control the server environment as much or devops, etc so it’s just easier to include the files in your project. Here’s how to tell Composer where the files are and how to load Spark.

First – Update composer.json

Similarly to the official install docs, you need to add a snippet to your composer.json file.

"repositories": [
     "type": "path",
     "url": "./spark-stripe"

In my case, I have a folder in the root of my project called spark-stripe in which I placed all of the package files. Does it matter what the name is? I don’t know but since that is the package name, it made the most sense to me.

Final – Install the Package

Lastly, you’ll need to install the package like you normally would. For what it’s worth, I’m using Composer v2.

composer require laravel/spark-stripe 

If you don’t see a new list of dependency packages being installed, you likely did something wrong. Go back and check your composer.json file for spelling errors or other mistakes.

Hope this helps you out!

How to add a Macro to the Laravel HTTP client facade

While working on Let Them Eat 🍰I came across some peculiar behavior. For some of the Slack web API’s, there is a requirement to send the requests as a URL encoded form object. Since all of their API endpoints support this method of access, I created a little helper on my user object to get an instance of the Laravel HTTP client, with the asForm() method already applied.

This was working great until today when I wanted to add support for blocks to one of my bot responses. While I could support sending that field as a JSON string, it felt better to change the request to be sent fully as JSON instead. I thought, that would be as simple as calling ->withHeaders() again, but unfortunately, the deep-recursive-merge used by the HTTP facade doesn’t clear out any existing values.


"headers" => [
  "Content-Type" => [
    0 => "application/x-www-form-urlencoded",
    1 => "application/json"

Obviously, the best option would be to not call the facade with multiple methods that change the same object, but in this case I really wanted to just overwrite it for this one instance.

Enter, Macros!

There are lots of places online to read about Laravel Macros so I won’t go into it here too deeply, but the gist of it, is you can add custom methods to core objects without extending them and creating new classes. This can be super helpful when you just want to add a little helper method but don’t want to go through the process of extending the class the old-fashion way. This can be especially useful to access protected properties or private methods.

I knew all facades in Laravel are macroable so I jumped into my AppServiceProvider boot method and added a lil somthin somethin.

// within AppServiceProvider::boot()
PendingRequest::macro('clearContentType', function () {
  $this->options['headers']['Content-Type'] = [];
  return $this;

Originally, I tried to add the Macro directly to the Http facade, but that only ended up working if I called the new method statically. To have it work in the manner I expected, I had to add the macro to Illuminate\Http\Client\PendingRequest, which is the class that is bound to the Http facade under the hood.

Using my new macro, I can easily clear out any content type headers before making a request, no matter how many times I call methods that set the content type header.


"headers" => [
  "Content-Type" => [
    0 => "application/json"

Now, I suspect this is a bug, but I’m not sure. I’ll be opening an issue on Github and we shall see. In the meantime, the macro will have to do! 🙂