Today I Learned

hashrocket A Hashrocket project

List Installed Fonts via the Command Line

Today I learned there's a command line utility called fc-list. It lists the fonts installed on your system.

Running fc-list will print out a lot of information - font families, the different styles available, where they're installed.

I find it's much more useful to run fc-list : family, which will print out all the font family names installed:

$ fc-list : family

Fira Code,Fira Code SemiBold
0xProto Nerd Font
Iosevka Term,Iosevka Term Extrabold
Menlo
.SF NS Mono
...

This is a lot easier to read and grep through!

My main use case for this is if I want to use a font in my alacritty config, but don't know the font's exact name. For example, if I want to use Apple's new(-ish) SF Mono font, the font family is not SF Mono as you might expect - its clearly .SF NS Mono 🤷.

Scoped Uniqueness Validation

Let's say you have a blog, with Authors and BlogPosts. A BlogPost has an Author and a title. If we have a requirement that the post titles need to be unique, our model would look something like this:

class Blog < ApplicationRecord
  has_one :author

  validates :title, uniqueness: true
end

Let's say the requirement changes, and the post title needs to be unique to the author (yeah it's convoluted, but let's roll with it). So Ann can author a post titled 'Cool Post', and Bob can also author 'Cool Post', but Ann can't publish another post titled 'Cool Post'.

Conveniently, uniqueness validations can be scoped to a particular attributes. So to satisfy the above, we can update the validation to:

class Blog < ApplicationRecord
  has_one :author

  validates :title, uniqueness: {scope: :author_id}
end

Tell Rails Your Foreign Key is a UUID

Let's say you have a blog with an Author model, and you want to create a blog_posts table. Each post has an author, and you want a foreign key on blog_posts to the Author's id.

class CreateAuthors < ActiveRecord::Migration[7.0]
  def change
    create_table :authors do |t|
      t.string :name
    end
  end
end

class CreateBlogPosts < ActiveRecord::Migration[7.0]
  def change
    create_table :blog_posts do |t|
      t.string :title
      t.text :content
      t.references :author, null: false, foreign_key: true

    end
  end
end

Pretty straightforward, right? But if Author#id is a UUID, you'll probably run into some issues with this migration. Rails by default assumes your table's IDs will be BigInt and if your IDs aren't then you need to specify the type in t.references:

class CreateAuthors < ActiveRecord::Migration[7.0]
  def change
    create_table :authors, id: :uuid do |t|
      t.string :name
    end
  end
end

class CreateBlogPosts < ActiveRecord::Migration[7.0]
  def change
    create_table :blog_posts, id: :uuid do |t|
      t.string :title
      t.text :content
      t.references :author, null: false, foreign_key: true, type: :uuid

    end
  end
end

Comparing Nullable values in PostgreSQL

PostgreSQL treats NULL values a bit different than most of the languages we work with. Said that, if you try this:

SELECT * FROM users WHERE has_confirmed_email <> TRUE

This would return users with has_confirmed_email = FALSE only, so NULL values that you have on your DB would be ignored. In this case if you want to get users with has_confirmed_email as FALSE or NULL then you can use IS DISTINCT FROM:

SELECT * FROM users WHERE has_confirmed_email IS DISTINCT FROM TRUE

Phoenix chunk huge files

So Phoenix, actually Plug, has a way to chunkify a response back to the client. This allowed us to create a stream out of an ecto query, then pipe that stream into a csv encoder and finally to Plug.Conn.chunk/2, which end up solving the huge memory spikes that we had when downloading a CSV. Here's a pseudo-code:

my_ecto_query
|> Repo.stream()
|> CSV.encode() # external lib that encodes from a stream into CSV
|> Enum.reduce_while(conn, fn chunk, conn ->
  case Conn.chunk(conn, chunk) do
    {:ok, conn} -> {:cont, conn}
    _ -> {:halt, conn}
  end
end)

Be informed of when a browser document is visible

A browser's visibilityState property is an essential aspect of web development that plays a crucial role in optimizing user experience and resource management in web applications. This property is part of the Page Visibility API, a web standard that provides developers with the ability to determine the current visibility state of a webpage.

The concept of visibility state revolves around whether a webpage is in a "visible" or "hidden" state. When a user navigates to a different tab, minimizes the browser window, or locks the screen, the webpage becomes "hidden". Conversely, when the webpage is in the foreground, and the user actively interacts with it, the state is "visible".

Add an error to an Ecto Changeset

If you want to create custom validations with ecto changeset, chances are you are going to need to add errors to the changeset to be shown to the user.

Using add_error/4 allows you to add an error to a changeset.

changeset = change(%BlogPost{}, %{content: "Hello World ...cont"})
add_error(changeset, :content, "Your blog content is too long!")

changeset.errors
[content: {"Your blog content is too long!", []}]

How to search case sensitively in Postgres

There's nothing special about this, I'm just a dummy who only ever used ilike and never thought twice about it.

Today, I learned that ilike is just a case-insensitive version of like.

This would return any rows with a name of Peter

select * from users
where name ilike '%peter%'
;

This would not return any rows with a name of Peter

select * from users
where name like '%peter%'
;

Stay tuned for tomorrow's TIL where I tell you about how I learned the sky is blue! 😂

Parseable npm audit output

In npm v6 and below, npm audit has a --parseable option that will output the audit report in plain text rows with tab delimiters. By default its a lot of information, but you can awk and grep/ripgrep to parse and filter down to what you want.

To only print the package name, vulnerability level and resolution, you can run:

% npm audit --parseable | awk -F $'\t' '{print $2, $3, $4}'

minimist critical npm update minimist --depth 15
immer high npm install react-scripts@5.0.1
loader-utils high npm install react-scripts@5.0.1
decode-uri-component high npm install react-scripts@5.0.1

And you can pipe that through to ripgrep to only show the critical vulnerabilities.

% npm audit --parseable | awk -F $'\t' '{print $2, $3, $4}' | rg critical

minimist critical npm update minimist --depth 15

In newer versions of npm, the --parseable option was dropped and instead you can use the --json option to output to json instead.

Disable database management tasks in Rails

If you wish to not have Rails manage migrations, seeds, schema changes, etc, you can add the database_tasks: false to your database.yml. This may be useful if you are "inheriting", sharing a database managed with some other system, or if you are connecting to a readonly database.

production:
  database: hashrocket
  adapter: postgresql
  encoding: unicode
  pool: 5
  database_tasks: false

https://guides.rubyonrails.org/active_record_multiple_databases.html#connecting-to-databases-without-managing-schema-and-migrations

Unsubscribe from `watchPositionAsync` in Expo

After seeing some very unexpected behavior, I went down the rabbit hole of StackOverflow, Reddit, and finally the Expo documentation for the function watchPositionAsync.

As it turns out, I had overlooked that this function returns a promise that resolves to a LocationSubscription. Meaning the following code does NOT work for obvious reasons.

Bad ❌

import { Accuracy, watchPositionAsync } from 'expo-location';

function Actions() {
   useEffect(() => {
      const subscription = watchPositionAsync(
        { accuracy: Accuracy.Balanced },
        coords => console.log(coords)
      );
      return subscription.remove();
    }, []);
  // ...
}

In order to get the subscription object, I had to let the promise resolve. This now looks like below.

Good ✅

import { Accuracy, watchPositionAsync } from 'expo-location';

function Actions() {
   useEffect(() => {
      let subscription;
      async function watchLocation() {
        subscription = await watchPositionAsync(
          { accuracy: Accuracy.Balanced },
          coords => console.log(coords)
        );
      }
      watchLocation();
      return subscription?.remove();
    }, [])
  // ...
}

Hooray documentation! 😅

https://docs.expo.dev/versions/latest/sdk/location/#locationsubscription

Create Environment Specific Rails Credentials

If you've worked with the rails encrypted credentials system before, you're probably familiar with the command to edit them

bin/rails credentials:edit

This will create(if it doesn't exist config/credentials.yml.enc by way of the RAILS_MASTER_KEY). If you only have this credentials file, the items in this file will be available to all environments of your application.

But you can also create/edit environment specific credentials by specifying an environment. This will similarly create 2 files - config/development.key and config/development.yml.enc.

bin/rails credentials:edit --environment development

Credentials specified in this file will only be available in the development environment

https://edgeguides.rubyonrails.org/security.html#custom-credentials

Use foreign-key like attributes with FactoryBot

An odd issue occurs when trying to use attributes similar to methods you'd expect with Rails ActiveRecord relationships in FactoryBot.

Take a relationship named provider. You would expect the ActiveRecord object to have methods for provider and provider_id.

However, some interesting behavior happens when you legitimately have a reason to have methods with those names, not during an ActiveRecord relationship.

FactoryBot.define do
  factory :widget do
    url { "URL" }
	provider { "PROVIDER_NAME" }
	provider_id { "PROVIDER_ID" }
  end
end

One will get cleared out when providing the attributes for provider and provider_id.

There is a long-running issue regarding this, but for now, this is how I could remedy the situation. Set the methods as transient attributes and merge the attributes during initialization.

FactoryBot.define do
  factory :widget do
    url { "URL" }

    transient do
      provider { "PROVIDER" }
      provider_id { "PROVIDER_ID" }
    end

    initialize_with do
      new(
        attributes.merge(
          provider: provider,
          provider_id: provider_id
        )
      )
    end
  end
end

ActiveRecord Strict Loading in Rails

When using ActiveRecord, lazy loading is the default behavior, where associated records are loaded when accessed. While convenient, this can lead to N+1 query problems, where an unanticipated number of database queries are triggered, potentially degrading performance.

Strict loading is a countermeasure to this issue. When enabled, it enforces the eager loading of associations, meaning all necessary data is loaded upfront in a single query. This approach mitigates the risk of N+1 queries and makes data fetching more efficient and predictable.

Strict loading can be set at various levels:

Globally: Set strict loading for all models by configuring it in the application:

config.active_record.strict_loading_by_default = true

Model Level: Enable strict loading for a specific model:

class Book < ApplicationRecord 
  has_many :chapters, strict_loading: true
end

Association Level: Apply it to specific associations:

has_many :comments, strict_loading: true 

Query Level: Use it on a per-query basis:

User.strict_loading.find(params[:id])

Optional routing segments in Rails

Optional routing segments in Ruby on Rails are a versatile feature in the framework's routing system, allowing for more flexible and dynamic URL structures. These segments are denoted by parentheses and can significantly streamline routing patterns.

For example, a route like:

get 'books(/:genre)', to: 'books#index' 

Here, :genre is an optional segment. This route will match /books and /books/fiction, routing them to the books#index action. The presence or absence of the genre parameter can be used within the controller to tailor the response.

Optional segments are handy for simplifying routes that cater to multiple URL patterns, reducing the need for numerous specific routes. They enhance the flexibility and readability of the code, making the application's URL structure more intuitive and user-friendly.

Get Screen Dimensions in React Native

Before today, I was familiar with the older Dimension API. However, you can use the hook useWindowDimensions to get screen size updates in a React Native component. The values returned by the hook will change as the screen size changes.

import { useWindowDimensions, Text, View } from "react-native"

function App() {
  const { width, height } = useWindowDimensions();
  
  return (
    <View>
      <Text>{width}</Text>
      <Text>{height}</Text>
    </View>
  )
}

https://reactnative.dev/docs/dimensions

https://reactnative.dev/docs/usewindowdimensions

Grab first N elements from an array

Have you ever wanted to grab the first n elements from an array?

You might think to do something like this:

fruit = ["apple", "banana", "blueberry", "cherry", "dragonfruit"]

# Grab the first 3 elements of the array
fruit[0...3]
=> ["apple", "banana", "blueberry"]

Well you could just use Array#take and tell it how many elements you want to take:

fruit = ["apple", "banana", "blueberry", "cherry", "dragonfruit"]

# Grab the first 3 elements of the array
fruit.take(3)
=> ["apple", "banana", "blueberry"]

Bonus: There is also Array#take_while which takes a block and passes elements until the block returns nil or false

fruit.take_while {|f| f.length < 8 }
=> ["apple", "banana"]
fruit.take_while {|f| f.length < 10 }
=> ["apple", "banana", "blueberry", "cherry"]

End of Line Substitutions in Vim

Today I learned a couple of nice regexes for substitutions in (n)vim.

Say you have a list, and you want to replace the character at the end of each line with something else:

123@
456@
789!

To replace the @s and ! with commas (,), you can use this substitute command :%s/.$/,/

123,
456,
789,

The regex .$ matches the character (.) that's at the end of the line ($)

Additionally, if you want to add something to the end of each line (but not replace), you can use the substitution :%s/$/,/ to transform

123
456
789

into

123,
456,
789,

Files Have Extended Attributes in OSX

I was looking into OSX's quarantine mechanism, and learned how downloaded executables are prevented from running. OSX uses extended attributes to prevent these from running, aka quarantine.

For example, if you install chromedriver with homebrew, then try to open it, you'll see that all too familiar alert that "the developer cannot be verified". How does OSX know to do this? Well, when the file is downloaded, it writes an extended attribute (com.apple.quarantine) key-value to the file (see Gatekeeper). These extended attributes hold additional metadata about each file.

In the terminal, you can view these attributes on a file with the xattr command.

> xattr -l /usr/local/bin/chromedriver
com.apple.quarantine: xxxxxxxxxxxxxxxxxxxxxxxx

You can manually remove an attribute with this utility using the -d flag -

> xattr -d com.apple.quarantine

https://ss64.com/osx/xattr.html

Compare NaiveDateTimes by a specific unit

In Elixir, you can get the difference between two NaiveDateTimes using the NaiveDateTime.diff/3 function.

The third arg allows you to pass a unit such as :microsecond, :millisecond, or any unit returned from System.time_unit. By default, the unit is set to :second.

NaiveDateTime.diff(~N[2014-10-02 00:29:18], ~N[2014-10-02 00:29:10])
#=> 8
NaiveDateTime.diff(~N[2014-10-04 00:29:18], ~N[2014-10-02 00:29:10], :day)
#=> 2

Interestingly enough :day works as a unit, but not :month, or :year. 🤔

Map with Index

Ever wanted map_with_index, like each_with_index except for map instead of each? Turns out you can, with just a 1 character change. with_index is a method on Enumerator that lets you do just that:

['a', 'b', 'c'].map.with_index do |x, index|
  [x, index]
end
#=> [["a", 0], ["b", 1], ["c", 2]]

Docs

Ruby Scan with Index

If you want to search for a pattern in a string and get back all the matches of that pattern, you can use String#scan:

irb(main)> "..123...456...123".scan(/\d+/)
=> ["123", "456", "123"]

This is super useful. But sometimes, it would be even more useful to also know the index of where the match starts. Turns out, you can do this with $~

irb(main)> matches_with_index = []
irb(main)* "..123...456...123".scan(/\d+/).map do |x|
irb(main)*   [x, $~.offset(0)[0]]
irb(main)> end
irb(main)> matches_with_index
=> [["123", 2], ["456", 8], ["123", 14]]

$~ is a global variable that's equivalent to Regexp.last_match, which is the MatchData for the last successful pattern match - it basically lets you get some data about the last thing Regexp matched.

MatchData#offsetreturns an array with the starting and ending offsets of the match. So $~.offset(0)[0] -> the offset to the start of the match, and $~.offset(0)[1] -> the offset to the end of the match.

Touch ActiveRecord::Associations

ActiveRecord::Associations#belongs_to has an option of touch.

If passed true, the associated object will have its updated_at/updated_on attributes set to current time.

You can also pass a symbol, in that case that attribute will be updated with the current time in addition to the updated_at/updated_on

class Comment < ApplicationRecord
  # When a comment is saved/destroyed, its post will
  # update the updated_at/updated_on to the current time
  belongs_to :post, touch: true

  # OR

  # When a comment is saved/destroyed, its post will update both
  # the updated_at/updated_on as well as comment_last_updated_at
  belongs_to :post, touch: :comment_last_updated_at
end

Note: No validations are performed when touching.

Custom email routing in Github

Is your Github account attached to multiple organizations? Does your primary address associated with Github get inundated with emails/notifications you don't care to find in your personal inbox?

Let me help you out by sorting your Github notification life. Get an email address to which you can flow relevant notifications and associate them with your Github account. Then head on over to Github > Settings > Notifications > Custom Routing

Click "Add new route" and choose an organization and an email address associated with your account.

Github custom routing settings page for notifications

As you can see, I have my primary email address with Github. Still, now all relevant notifications from Hashrocket projects will funnel into my Hashrocket email address.

Easily skip tests in Jest

Using skip in Jest tests is a valuable technique for temporarily disabling specific tests without completely removing them from your test suite. This is particularly useful during development when you focus on one particular feature or bug and want to avoid running unrelated tests to save time. In Jest, you can use skip by prefixing it to your test or describe blocks.

For instance, test.skip(...) or describe.skip(...) will skip the execution of the specified test or group of tests. This approach is much more maintainable than commenting out tests, as it keeps the test code intact and easily readable.

Moreover, skipped tests are reported in Jest's output, reminding you that there are tests that need attention. This feature is convenient when working in a team environment, as it allows developers to be aware of tests that are not currently active but are still part of the overall test plan. It also helps ensure that all tests are eventually re-enabled and the test coverage remains comprehensive.

String Concat Pattern Matching In Elixir

This is a neat pattern matching trick in elixir, its best explained with a simple example:

invoice_message = "You owe $34"
"You owe " <> dollar_amount = invoice

IO.inspect(dollar_amount)
# => "$34"

With a slightly different situation, It may seem like you could do this:

invoice_message = "You owe 34 dollars"
"You owe " <> dollar_amount  <> " dollars"= invoice

IO.inspect(dollar_amount)
# => ** (ArgumentError) the left argument of <> operator inside
# a match should always be a literal binary because its size can't be verified. Got: dollar_amount

But sadly you'll need to use regex to do that because elixir will throw an error.

Only Pick certain properties in Typescript

In TypeScript, the Pick utility type provides a flexible way to construct new types by selecting subsets of properties from existing ones. For example, consider an interface User:

interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}

// Using Pick to create a new type type
UserContactDetails = Pick<User, 'email' | 'name'>;

In this example, UserContactDetails is a new type with only the email and name properties from the User interface.

This is particularly beneficial when you must pass or manipulate only specific aspects of a complex type, ensuring type safety and reducing the risk of handling unnecessary or sensitive data. By tailoring types to particular use cases, Pick enhances code maintainability and readability, streamlining development processes in TypeScript applications.

saved_changes & previous_changes in Rails

In Ruby on Rails, saved_changes and previous_changes are methods used to track changes in Active Record models. saved_changes is used after an object is saved to the database. It provides a hash of all the attributes changed when persisting an object, including their original and final values. This method helps understand what changes have just persisted. On the other hand, previous_changes is used after an object is saved but before reloading. It holds the same information as saved_changes but becomes available only after the save operation and before the object is reloaded. It is helpful for actions triggered immediately after a save, like callbacks or logging changes.

Both methods are instrumental in tracking attribute changes and responding to them effectively in a Rails application.

Verify current password with has_secure_password

Now with Rails 7.1, has_secure_password can now automatically verify the current password when updating the password. This is useful to check if the user who is trying to update the password, knows the current password:

class User < ActiveRecord::Base
  has_secure_password
end

user = User.new(password: "sekret", password_confirmation: "sekret")
user.save
#=> true

user.update(password: "HAHAHA", password_challenge: "")
#=> false, challenge doesn't authenticate

user.update(password: "updated*sekret", password_challenge: "sekret")
#=> true

Mock External Library Functions in Jest

Suppose you import two functions from an external library in one of your js files:

import { func1, func2 } from "externalLib";

export const doSomething = () => {
  func1();
  func2();
  // ...
};

Now let's write a test for this function, and say we want to mock func1.

describe("doSomething", () => {
  jest.mock("externalLib", () => ({
    func1: jest.fn(),
  }));

  it("does something", () => {
    func1.mockImplementation(...);
    // ...
  });
});

But oh no! This test will fail - we inadvertently blew away the rest of the implementation of externalLib when we created the mock for func1. Since doSomething relies on other functions in externalLib, we get errors.

In order to preserve the rest of the implementation of externalLib and only mock func1, we need to call requireActual and spread it's return into the mock to get the implementation of the rest of the library:

describe("doSomething", () => {
  jest.mock("externalLib", () => ({
    ...jest.requireActual("externalLib"),
    func1: jest.fn(),
  }));

  it("does something", () => {
    func1.mockImplementation(...);
    // ...
  });
});

Et voilà, your test will pass ✅.

Running a Single Jest Test

Jest runs tests in parallel by default, file by file.

That means if you add a .only on an it or describe, that only applies in the context of a single file. So if you have a test suite with 5 different test files and execute tests with jest, 4 test files will run all their tests and one file will run it's only test.

If you want only a single test to run, you need to add that .only and narrow jest's scope to that single test file: jest src/path/to/test.js.