Today I Learned

A Hashrocket project

Specify different bundler groups with RAILS_GROUPS

Is there a gem that you want to include sometimes and not others? For instance, do you have multiple versions of staging with slightly different gemsets? You can manage that with custom groups.

group :apple do
  gem 'some_gem'

group :orange do
  gem 'some_other_gem'
RAILS_GROUPS=apple,orange rails console
> Rails.groups
[:default, "development", "apple", "orange"]

In the config/application.rb file, Rails.groups is passed to Bundler.require.


A React Component Is Just A Bag Of Data

If you write enough React using JSX, it is easy to forget that you’re not working with markup. Everything — divs, h1s, 3rd party components, your components — all get boiled down to JavaScript objects full of data.

Any given React component is really just a bag of data. Try doing a console.log to see. Here is an example from an earlier post.

const ParentWithClick = ({ children }) => {
  return (
      { || null, (child, i) => {
        return <child.type {...child.props} key={i} onClick={handleClick} />;

const App = () => (
      <span>Click this span</span>

Looking in the console, we see the following output:

Object {type: "span", key: null, ref: null, props: Object, _owner: Object…}
 type: "span"
 key: null
 ref: null
 props: Object
  children: "Click this span"
 _owner: Object
 _store: Object

It contains information about the component itself and because of the tree structure of this data, you could potentially expand the props —> children sections several times for certain components.

See a live example here.

Change Name of :id Param in Rails Resource Routing

You can change the name of the parameter used by rails resource routing by specifying the param option to the resource route.

For example, if we have a show endpoint:

resources :pages, only: :show

Running rake routes will return the pages#show url as:


We can change the id param to slug by doing:

resources :pages, only: :show, param: :slug

Then running rake routes will yield our new pages#show route as:


Shell into a stopped docker container

If you are experiencing an error trying to run your docker container then maybe you need to do some debugging inside of the docker container. But how do you shell into a container if you can’t even start it?

docker run -it --rm --name newname myimage:latest bash

This takes your image and starts a new container, running bash and allowing you to examine your container.

-it allows you to attach a terminal.

--rm will clean this container up when you are done with it.

--name <something> is the name you give your new container.

Download/Upload Redux Store In Chrome DevTools

People explaining the value of Redux as a JS state solution often point out that it’s designed to support great developer tools. Today I got a better understanding of what that means.

Chrome DevTools currently includes the toolbar shown below. The upload and download buttons, fourth and third from right, allow you to download, inspect (and edit), and upload the Redux store as a JSON file.

This is seems like a fantastic way to debug situations that might be difficult to reproduce through user interactions.

Remove indentation from heredocs

Ruby heredocs are a convenient way to include a block of text in Ruby source. Unfortunately, if the text is indented properly with the rest of the code the actual string is also indented. This is often undesired. However, it can be fixed by using the squiggly heredoc.

lorem = <<~STR
  Lorem ipsum dolor sit amet,
  consectetur adipiscing elit,
  sed do eiusmod

lorem #=> => "Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit,\nsed do eiusmod\n"

The squiggly heredoc automatically removes any indentation that is applied to all lines.

Spread The Rest With ES6

The spread operator provided by ES6 is a powerful syntactic feature. One way it can be used is to capture the rest of an object or array in a variable.

const pokemon = ["Charmander", "Squirtle", "Bulbasaur"];
const [first,] = pokemon;

console.log("Remaining: ", rest); // Remaining: ["Squirtle", "Bulbasaur"]

const gymLeaders = {
  brock: "rock",
  misty: "water",
  surge: "electric",
  erika: "rainbow"
let { brock, erika, ...otherLeaders } = gymLeaders;

console.log(otherLeaders); // Object {misty: "water", surge: "electric"}

Using this spread destructuring we can capture the remaining parts of an array or object in a variable. We can also use this syntax in a function signature to grab specific items from an incoming object argument without losing track of the rest — this is especially useful in React.js development when dealing with incoming props.

This is a stage 3 feature and may not be available in your particular environment.

See a live example here.

Your slowest Elixir tests

Sometimes its handy to see what tests are taking the longest in an Elixir project.

Enter mix test --slowest N

Just replace N with how many slow tests you would like to see and you’ll get some handy output:

$ mix test --slowest 5

Top 5 slowest (17.6s), 30.2% of total time:
  * test enters a body that is too long (4504.4ms) (DeveloperCreatesPostTest)
  * test the page does not have a Create Post link (4384.9ms) (VisitorVisitsHomepageTest)
  * test and clicks 'like' for that post (3944.2ms) (VisitorViewsPostTest)
  * test fills out form and updates post from post show (2558.6ms) (DeveloperEditsPostTest)
  * test fills out form and submits (2255.5ms) (DeveloperCreatesPostTest)

Mapping Over One Or Many Children In React

In Dynamically Add Props To A Child Component, I talked about how a child element can be reconstituted with additional props. The approach I showed will only work in the case of a single child being nested in that component. What if you want your component to account for one, many, or even children?

React comes with a built-in function for mapping that handles these cases.

const ParentWithClick = ({ children }) => {
  return (
      { || null, (child, i) => {
        return <child.type {...child.props} key={i} onClick={handleClick} />;

The function allows mapping over one or many elements and if children is null or undefined, it will return null or undefined respectively.

See a live example here.

Using an array literal to specify length

Go forces you to specify the length of an array when creating or declaring an array. If you don’t declare the length then its not an array its a slice. The syntax for declaring the array looks like this:

// array of length 3
var numbers = [3]int{1, 2, 3}

When we use an array literal with the {} to declare the values of an array, the length declaration becomes redundant.

var numbers = []int{1, 2, 3}

The above example, however shows the declaration of a slice not an array. To let the literal define the length of an array we can place the ... operator inside the [] square brackets.

var numbers = [...]int{1, 2, 3}

Now, we can add a fourth element to the array without also having to change the specified length.

Clip images in html with `clip-path`

You may have some images that have some annoying artifacts around the border, or maybe you just want an image to be a funky shape for design purposes. If so, then clip-path is the css property for you.

Check out this diamond shaped image from the mdn docs:

clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);

There are 4 functions, circle, ellipse, polygon, and inset, amongst a number of interesting options, some of which work in your browser currently, some of which may not.

Creating a vector for your specific shape might sound rough, but firefox has a built-in clip-path tool that can help you set it correctly in the browser.

Dynamically Add Props To A Child Component

If your component has an element nested in it, then it will receive a children prop. There are a number of things you can do beyond simply including the children as part of the rendered output of the component. One thing you can do is put additional props on the child.

const ParentWithClick = ({ children }) => {
  return (
      onClick={() => alert("You clicked me!")}

This ParentWithClick component will reconstitute its child component with its given props and a new onClick prop.

Here is how it can be used:

const App = () => {
  return (

Click on Hello! and you’ll see the alert.

Minor caveat: multiple children and a string child will need to be handled differently.

See a live example here.

Who Is Your Favorite Child?

When we put some content inside the open and close tags of one of our components, we get access to it as the children prop.

const Parent = ({children}) => {
  return (
      <p>These are my favorites:</p>

const App = () => (
      Greg and Marsha

What happens if we also provide an explicit children prop to Parent?

const App = () => (
    <Parent children={"Jan and Peter"}>
      Greg and Marsha

Which will take precedence when we destructure children in the parent component?

In the example above, we’ll still see Greg and Marsha rendered. The content placed inside the tags will take precedence over the explicit children prop.

See a live example here.

Rearrange items with `grid-template-areas`

You can arrange items with the css-grid property grid-template-areas without changing the structure of your html.

Here I have basic strategy for a 2x2 grid with item one in the upper left corner and item four in the lower right.

.container {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
    "one two"
    "three four";

.one { grid-area: one }
.two { grid-area: two }
.three { grid-area: three }
.four { grid-area: four }

I can rearrange my items just by changing the grid-template-areas property:

.container {
    "four two"
    "three one";

Now, item four is in the upper left corner, and item one is in the lower right.

A complete example is up at CodePen

Difference between output of two commands #linux

Recently I’ve been playing around with ripgrep (rg) which is a tool similar to Ack and Ag, but faster than both (and written in Rust FWIW).

I noticed that when I ran a command in Ag to list all file names in a directory, and counted the number of files shown, I was getting a different number than the comparable command in ripgrep.

ag -l -g "" | wc -l
# =>      29
rg -l "" | wc -l
# =>      33

This led me to wonder if there is an easy way to view the diff between the output of the two commands.

I know I can save the output into a file and then compare the two files with the builtin diff command in linux, however I don’t see a reason to write to disk for such a comparison.

This is how you would do that without writing to disk:

diff <(ag -l -g "") <(rg -l "")

The diff printed out by this command is inaccurate, so you will need to add a sort to each command:

diff <(ag -l -g "" | sort) <(rg -l "" | sort)

Use Go Printf argument twice with adverbs

Usually, when you use one of the format functions from the fmt library you pass in one argument or operand for each verb you use.

fmt.Printf("Hello %s, nice to meet you %s", "Lauren", "Harry")
// Prints --> Hello Lauren, nice to meet you Harry

But what if you want to use one of those operands twice? Well, you can use what go terms an adverb. Place square brackets after the percent symbol with an index that refers to the argument you’d like to use.

fmt.Printf("Hello %s, nice to meet you %[1]s", "Lauren")
// Prints --> Hello Lauren, nice to meet you Lauren

Azure key discovery provides modulus and exponent

To verify a JWT coming from Azure, you must provide the ruby JWT package a public key. That public key must be OpenSSL::PKey::RSA value.

The Azure key discovery url provides this public key definition:

  "keys": [
      "kid": "X5eXk4xyojNFum1kl2Ytv8dlNP4-c57dO6QGTVBwaNk",
      "nbf": 1493763266,
      "use": "sig",
      "kty": "RSA",
      "e": "AQAB",
      "n": "tVKUtcx_n9rt5afY_2WFNvU6PlFMggCatsZ3l4RjKxH0jgdLq6CScb0P3ZGXYbPzXvmmLiWZizpb-h0qup5jznOvOr-Dhw9908584BSgC83YacjWNqEK3urxhyE2jWjwRm2N95WGgb5mzE5XmZIvkvyXnn7X8dvgFPF5QwIngGsDG8LyHuJWlaDhr_EPLMW4wHvH0zZCuRMARIJmmqiMy3VD4ftq4nS5s8vJL0pVSrkuNojtokp84AtkADCDU_BUhrc2sIgfnvZ03koCQRoZmWiHu86SuJZYkDFstVTVSR0hiXudFlfQ2rOhPlpObmku68lXw-7V-P7jwrQRFfQVXw"

First, I tried using the n value to create a ruby public key:

OpenSSL::PKey::RSAError: Neither PUB key nor PRIV key: nested asn1 error

So n is not the public key? WTF is n. Via the wikipedia page for RSA.

Alice transmits her public key (n, e) to Bob via a reliable, but not necessarily secret, route

n is the modulus. e is the exponent (in this case AQAB), but the ruby library requires a pem. We must convert the modulus and exponent to a pem. Luckily there is a gem for that:

gem install rsa-pem-from-mod-exp

Convert to a pem then to a pubkey:

require 'rsa_pem'

pem = RsaPem.from(key['n'], key['e'])

public_key =

And verify your token

decoded_token = JWT.decode token, public_key, true, { :algorithm => 'RS256' }

Python and Neovim

Some Vim plugins require Python, and if you’re using NeoVim, you’ll need to do a bit of extra work to get them working. An error message like this, seen when Python is definitely installed on your machine, is a hint you’re in this predicament:

$ vim
MatchTagAlways unavailable: requires python

Neovim needs its own Python support. Solve the problem with this library, specifically one of the following commands depending on your Python version:

$ pip2 install neovim
$ pip3 install neovim

In Go, NaN does not equal NaN

It’s false, it returns false.

fmt.Println(math.NaN == math.NaN)

Don’t fret though, there is a function that can tell you whether or not a value is NaN.


The above returns true and all is well with the world. Don’t use math.NaN as a sentinel value, it does not work, use the math.IsNaN function.

Custom Type Checking Error Messages With Yup

In Yup Schemas Are Validated Asynchronously, I showed how to create a simple schema that allows you to enforce that a value is a number.

const numSchema = yup.number();

If we use this schema to validate something that isn’t a number, Yup will provide a lengthy default message. Here is what we get if we validate against 'hey':

this must be a number type, but the final value was: NaN (cast from the value "hey").

This value isn’t necessarily suitable for displaying to a user. We can customize the type checking error message by redefining our schema with the typeError() function:

const numSchema = yup.number().typeError("Invalid number");

React Router Route can call a render function

In General, the React Router Route component looks like this.

<React path="/triangles" component={Triangles} />

If the current url matches /triangles then the Triangles component will render.

If you want to render something simple however, you can pass down a function with the render prop.

<React path="/helloworld" render={this.renderHelloWorld} />

With that function defined in the same parent component and returning some jsx

renderHelloWorld = () => {
  return (
    <div>Hello World!</div>

Parse JSON into an OpenStruct

When you parse json in ruby it is placed into a hash, and you have to access the values with hash syntax:

parsed_data = JSON.parse('{"color": "blue"}')
puts parsed_data["color"] # prints 'blue'

But instead of a hash you can choose to parse it into an OpenStruct by using the object_class option. Then you can use ruby’s method syntax to access the data.

parsed_data = JSON.parse('{"color": "blue"}', object_class: OpenStruct)
puts parsed_data.color # prints 'blue'

H/T Dillon Hafer

Yup Schemas Are Validated Asynchronously

Yup provides a flexible object schema validation DSL. For instance, if you want to enforce that a certain value is a number, you can define something like this:

const numSchema = yup.number();

You can then validate anything against that schema.

const validator = (val) => {
    .then(result => {
      console.log(result); // it is the value of `val`
      return true;
    .catch(error => {
      console.log(error.errors); // array of validation error messages
      return false;

The validation is async, so if it succeeds the then block is hit. If the validation fails, it will fall through to the catch.

validator(5) // => true
validator('what') // => false

Promises and then function return values

The return type of Promise function will dictate how future chained then functions behave. If you return a Promise then the next chained then function will execute when the Promise that you returned is resolved.

  then(() => {return Promise.resolve('bar')}).
  then((v) => console.log(v))

// prints bar

If you return something different from the then function, then the argument of the next chained then function will be the previous returned value.

  then(() => {return 'baz'}).
  then((v) => console.log(v))

// prints baz

Check out the MDN docs for Promise.prototype.then

H/T Brian Dunn

H/T Josh Branchaud

Build For A Specific OS And Architecture

Go programs can run anywhere, but you’ve got to create builds specific to each operating system and architecture. This can be done when building by specifying the GOOS and GOARCH environment variables.

For example, if you’d like to build a 32-bit Linux distribution:

GOOS=linux GOARCH=386 go build -o linux_386_build

The GOOS value specifies the operating system as Linux and the GOARCH value of 386 specifies a 32-bit architecture.

The plethora of GOOS and GOARCH options can be found here.

Three syntactical elements that return 2 values

golang supports multiple return values from functions but there are also 3 different syntactical elements or accessors that also return 2 values.

The most straight forward is accessing values from a map.

colors := map[string]string{
  "ocean":  "blue",
  "forest": "green",
  "jet":   "black"

x, ok := colors["ocean"]

Type assertions also want to let you know that they’re ok, like when we try to assert an error as a json.SyntaxError. Yeah, its a SyntaxError, ok?

synerr, ok := error.(*json.SyntaxError)

Channels can also let the program that things are going ok when using the receive syntax <-.

receivedValue, ok := <- ch

`new` returns a pointer, not a value

Go has pointers, which is great, I’ve never worked in a language with legit pointers before. The built-in function new returns a pointer.

p := new(int)

p is now a pointer. You can access the value of the pointer with the * syntax.


The above returns 0.

Read the documentation about new with:

go doc

React Anti-Pattern: defaultValue

The use of defaultValue isn’t strictly an anti-pattern, as with everything it’s context dependent. In the context of a small one form react component doing something simple I’d say defaultValue is fine. This is React in-the-small.

React in-the-large or in-the-massive is different. In large applications things change in unforseen ways. In large applications there are explicit or implicit frameworks that are upstream from your component and will affect the operation of your component. React-in-the-large will create multiple entry points to your component. Sometimes its history.push and sometimes its good ol’ Page Refresh. The state of your application will be different in both those cases.

In software that can change in many ways, defaultValue is brittle. Once rendered, an input with defaultValue is completely out of React’s hands. The value of the input cannot be changed when new information becomes available. You can change the value of the input with DOM functions, but then you’re not using React.

Outside of using a React form abstraction value is much more adaptable than defaultValue. It’s more work to setup and maybe harder to get right initially, but far more likely to suit your needs down the road.

🔢 CLI to bump iOS target versions

Bumping Info.plist versions by hand can be very error prone (e.g. remembering to bump multiple targets in a project)

Fortunately Xcode’s cli has an easy solution

xcrun agvtool new-marketing-version <versString>

So if my Application targets are at version 2.0.4 and I need them to be at 2.0.5 I simply run this command at the terminal:

xcrun agvtool new-marketing-version 2.0.5


Go docs at the command line

Go has plentiful documentation online, but sometimes using a search engine to find the right thing in go can be tough. Go has docs at the command line though.

You can go doc <name-of-package>

> go doc io/ioutil
package ioutil // import "io/ioutil"

Package ioutil implements some I/O utility functions.

var Discard io.Writer = devNull(0)
func NopCloser(r io.Reader) io.ReadCloser
func ReadAll(r io.Reader) ([]byte, error)
func ReadDir(dirname string) ([]os.FileInfo, error)
func ReadFile(filename string) ([]byte, error)
func TempDir(dir, prefix string) (name string, err error)
func TempFile(dir, prefix string) (f *os.File, err error)
func WriteFile(filename string, data []byte, perm os.FileMode) error

Or, you can go doc <function> if the function is fully qualified with the package name.

> go doc io/ioutil.WriteFile
func WriteFile(filename string, data []byte, perm os.FileMode) error
    WriteFile writes data to a file named by filename. If the file does not
    exist, WriteFile creates it with permissions perm; otherwise WriteFile
    truncates it before writing.

go doc ioutil.WriteFile will also work.

Link A JavaScript Package Locally

If you are putting together a JavaScript package and you’d like to test it out locally before putting it on NPM, use npm link.

First, from the directory of the package you are creating run:

$ npm link

This will symlink the package to the global node modules directory.

Then, from the base project directory that you want to try importing and using the package from, run:

$ npm link name-of-package

This will create an additional symlink from the global node modules directory to the node_modules of this target project.

You’ll now have access to the project, try an import to get what you need and try it out.

See man npm-link for more details.

Selecting DOM Elements Faster Than Ever In Chrome

Selecting and inspecting DOM elements: you’ve done it many times before. Whether you right click the element and select Inspect (which isn’t always all that accurate) or you use the DevTools’ inspect tool with highlight-assist, it takes a couple clicks to get there.

There is a faster way.

Hit Cmd-Shift-C.

Chrome DevTools will be expanded open if it isn’t already and your mouse pointer will be put in inspect mode with the highlight-assist. Find your DOM element, give it a click, and start inspecting!

Delayed Job Queue Adapter in RSpec with Rails 5.1

In old versions of Rails, you were able to override the ActiveJob queue in a test like this:

describe MyJob do
  it 'works' do
    ActiveJob::Base.queue_adapter = :delayed_job
    expect {
    }.to change(Delayed::Job.count).by(1)

With Rails 5.1, we have the ActiveJob::TestHelper class which you will need to employ in your tests. In order to override the queue a different strategy is needed.

describe MyJob do
  def queue_adapter_for_test
  it 'works' do
    expect {
    }.to change(Delayed::Job.count).by(1)

You will need to add the following to your rspec config or a support file:

RSpec.configure do |config|

# you will also need the code below for the test
# to clear out the jobs between test runs
class ActiveJob::QueueAdapters::DelayedJobAdapter
  class EnqueuedJobs
    def clear
      Delayed::Job.where(failed_at:nil).map &:destroy
  class PerformedJobs
    def clear
      Delayed::Job.where.not(failed_at:nil).map &:destroy
  def enqueued_jobs
  def performed_jobs

CircleCI Build Forked Pull Requests

Today I learned that CircleCI does not build against forked pull requests by default. You have to enable it under ‘Advanced Settings’.

This is important if your .circleci/config.yml contains build steps like running an automated test suite, linter, or autoformatter. With this setting enabled, every PR goes through the same motions before human review, whether coming from inside or outside the project organization.

Use withRouter To Pass Down React-Router History

A standard way to navigate with react-router besides using the Link component is to call history.push. Components that are directly rendered by a Route will have access to this and other router props. But what about other components?

The withRouter HOC gives us direct access to a history prop.

import React from 'react';
import { withRouter } from 'react-router';

const SpecialButton = withRouter(({ history, path, text }) => {
  return (
      onClick={() => { history.push(path); }}

This special button component is given the history prop via the withRouter HOC along with any props that we directly pass it. With that we are able to directly invoke a route change using history.push().

Access Go Docs Offline

The Go language has a wonderfully comprehensive standard library. There is documentation for all of it. You can access that documentation anytime if you have an internet connection via

If you are without an internet connection, you’re still in luck. Go has a built-in feature for serving the documentation locally offline. Just run the following command:

$ godoc -http=:6060

and then visit localhost:6060.


Read Only Input Elements With React

Here is an input element with a value and no onChange handler.

const MyInput = ({ value }) => {
  return (
    <input value={value} />

React will raise a warning regarding the input element because it has a value without an onChange handler leaving React to wonder if it is intended to be a controlled or uncontrolled component.

If our intention is to have the value set but not allow the user to directly change it, we just need to let React know that.

const MyInput = ({ value }) => {
  return (
    <input readOnly value={value} />

The readOnly prop means we don’t intend for the input to be modified by user input. The React warning will now go away.

h/t Dillon Hafer

Easier Access To Network Throttling Controls

In Simulating Various Network Connection Speeds, I showed how to change between various simulated connection speeds from the Network tab in Chrome devtools. Unfortunately, the Connection Speed dropdown is crowded out by a number of other controls in the Network tab. As a result, unless that tab is expanded pretty wide, you won’t be able to get at it. I’ve found myself sliding the devtools wider and narrower over and over while testing things with throttling.

There is another, easier place to access throttling.

The console drawer gives us access to a number of additional tabs of controls. Add the Network connections tab for easier access.

Escaping Terminal Mode In An Nvim Terminal

A recent TIL by Chris Erin showed how to split open a terminal in a Neovim session — :sp term://zsh.

The terminal is emulated into a Vim buffer which means that you can treat it sort of like any other Vim buffer. You start in Normal mode. Once you use any mapping that would transition you into Insert mode, you’ll instead find yourself in Terminal mode. Terminal mode works just like any zsh session (give ls a try).

Try hitting <Esc> though and you’ll see that you stay in Terminal mode instead of being transitioned back to Normal mode.

So how do you get back to Normal mode?

Hit <Ctrl-\><Ctrl-n>.

This is a pretty awkward key mapping though, so follow the Nvim Terminal docs and bring back the Escape key.

:tnoremap <Esc> <C-\><C-n>

Open a zsh terminal in a split window in Neovim

Opening a terminal in Neovim is one of the more eye opening features of the vim fork. To open a terminal in vim use the :terminal command.


Those commands though will use your entire current window for the terminal and by default it opons in bash even though my shell is configured to be zsh

To open a terminal in zsh use:

:te zsh

This still takes up the entire window. Lets now use the split command and the terminal protocol syntax to open a split window with zsh.

:sp term://zsh
:split term://zsh

List Top-Level NPM Dependencies

The npm ls command can be used to list all dependencies for a project. This will, however, produce an exhaustive list of all dependencies including dependencies of dependencies. A list this large probably isn’t going to be of much use.

The --depth flag allows you to restrict the depth of the dependency tree that is generated.

$ npm ls --depth=0

This will produce a list of only the top-level dependencies.

See man npm-ls for more details.

Destructure Variables As Props To A Component

When passing down props, a redundant-feeling pattern can sometimes emerge.

const MyComponent = ({ handleChange, handleBlur }) => {
  return (
      <OtherComponent />
      <MySubComponent handleChange={handleChange} handleBlur={handleBlur} />

The typing feel duplicative, as if there ought to be a better way. One option is to simply pass down all the props:

<MySubComponent {...props} />

This approach may result in passing down props that we don’t intend to pass down and clutters the flow of data in our app.

Here is another approach:

const MyComponent = ({ handleChange, handleBlur }) => {
  return (
      <OtherComponent />
      <MySubComponent {...{handleChange, handleBlur}} />

Here we are taking advantage of two ES6 features. Since the naming is the same, we can use property shorthands. Then we immediately use the spread operator to splat it back out as the props to the component.

h/t Vidal Ekechukwu

🔑 Set foreign keys to null

Sometimes, in certain circumstances, it is reasonable to have a foreign key value of null.

ActiveRecord’s .has_many method has an argument to set the foreign key column on referencing rows to null when that record is deleted.

dependent: :nullify


class Post < ApplicationRecord
  belongs_to :author
  belongs_to :category

class Category < ApplicationRecord
  has_many :posts, dependent: :nullify

In this example whenever a category is deleted, any posts referencing the categories table will have their foreign key set to null.