Today I Learned

hashrocket A Hashrocket project

3 ways to clear the terminal

Option 1:
Simply typing the terminal command clear will clear your terminal. This method preserves your current terminal session, meaning you can scroll up to see what was cleared away.

Option 2:
Pressing CTRL+L to clear away the terminal. This behaves essentially the same as the clear command, preserving your terminal session.

Option 3:
Pressing CMD+K to clear away the terminal. This behaves similarly to the other 2 options, except that it does not preserve your session.


h/t Vinicius Negrisolo

Run a rake task from within your Rails application

I was curious if I could trigger a rake task from within my Rails application.
After some digging, I found Rails::Command.invoke() which lets you run rake tasks from inside your Rails app.

Here's an example using db:migrate:

Rails::Command.invoke('db:migrate')

Just pass it the name of your task (db:migrate, your_custom_task, etc) and it will begin processing it.

This is great for automating or triggering rake tasks during bootstrapping or background operations without needing to leave the Rails environment.

Deleting Words in the Terminal

I stumbled upon this earlier today, if you're in a terminal and have typed some things in, pressing Esc, then Backspace will delete the word on or before your cursor. Ctrl + W will do the same thing.

So if I start typing a word and want to

$ one two three four 
                    ^ cursor here

Then Esc, Backspace will produce

$ one two three
               ^ cursor here

It deletes through the beginning of the word, but starts where the cursor is, so you can delete partial if your cursor is in the middle of a word

$ longer command here
            ^ cursor here

Then Esc, Backspace will produce

$ longer and here
         ^ cursor here

Confirmed both work in recent versions of bash and zsh.

Tables in Markdown

To create tables in a markdown file, you can use this syntax:

| Header 1 | Header 2 | Header 3|
| --- | --- | --- |
| Content 1 | Content 2 | Content 3 |
| Content 4 | Content 5 | Content 6 |

And this will output something like this, depending on what you are using to interpret the markdown:

image


I find this to be useful when displaying side-by-side images in a Github PR

Here is a silly example:

Post Office (B&W) Post Office (Colorized)
image image

h/t Vinicius Negrisolo

Run Script on Login/Start in Windows

You can automatically run a script on Windows during login by placing files in your users "Programs\Start Up" folder. It's useful for running *.bat scripts.

You can easily access this location by opening the "Run" dialog - Windows + r and typing shell:startup.

If you're an admin, you can also set this for all users by typing shell:common startup, which will open the shared Start Up folder.

If this is too much, you can also accomplish a similar thing by creating a "Scheduled Task". In the Windows search bar, type "Task Scheduler". Open this then click "Actions" -> "Create Task"

Count Commits within Time Range in Git

git rev-list lists commit objects in reverse chronological order, and as such is an incredibly powerful tool for inspecting your repository.

For example, if you wanted to count all your commits, you can with git rev-list --count HEAD.

You can also drill down to a specific time range with the --before and --after options. To get the count of all commits during 2024, you can run:

git rev-list --count --after="2024-01-01" --before="2025-01-01" HEAD

There are tons of other options you can use to filter this down too, by author, committer, etc.

Omitting specific fields in TypeScript types

TypeScript has an Omit utility type that lets you create a new type by excluding specific keys from an existing type. It's perfect for cases where you need a type that's almost the same but without certain properties.

Here's an example:

type User = {
  id: number;
  name: string;
  password: string;
};

type PublicUser = Omit<User, 'password'>;

Now we have a PublicUser type that includes id and name, but the password field is excluded.

h/t Vinicius Negrisolo

Change font size in iPhone simulator from keyboard

We found it very annoying to navigate to settings>accessibility>display>larger text just to verify that things still look good on phones with larger font sizes.

Turns out you can adjust the font size of the simulator much quicker using the following keyboard shortcuts:
CMD+Option++ to increase the font size of the device
CMD+Option+- to decrease the font size of the device

NOTE!
Just keep in mind, even if you have Larger Accessibility Sizes toggled off, you can still get to the larger font sizes this way.

Get React Native Component's Dimensions

In React Native you can use the onLayout prop along with the nativeEvent's layout to get the dimensions (in pixels) of a rendered component.

const [viewDimensions, setViewDimensions] = useState({height: 0, width: 0})
return (
  <View
     onLayout={(e) => setViewDimensions(e.nativeEvent.layout)}
  />
)

Now we have an object containging our view's height and width saved as viewDimensions

ActiveRecord.invert_where

Ever been debugging in ActiveRecord and wanted to inverse a query? You can do that without changing the whole query!

User.where(active: true)
# => "select * from users where active = 'true'"

User.where(active: true).invert_where
# => "select * from users where active != 'true'"

It also works with multiple conditions:

User.where(active: true, subscribed: false)
# => "select * from users where active = 'true' and subscribed = 'false'"

User.where(active: true, subscribed: false).invert_where
# => "select * from users where active != 'true' and subscribed != 'false'"

It works on scopes, too:

class User < ActiveRecord::Base
  scope :active, -> { where(active: true) }
end

User.active.invert_where
# => "select * from users where active != 'true'"

Managing Return Value of ActiveRecord Transactions

I recently ran into a situation where I wanted to know the return state of a transaction in ActiveRecord. Basically, I wanted to know if it succeeded or failed, then return true/false.

There's 3 scenarios to keep in mind to when trying to use this approach:

  1. Transaction succeeds - the last line of the transaction is the return
    class TestModel
     def save
       result =
         ActiveRecord::Base.transaction do
           SomeModel.last.touch
         end
    
       result
     end
    end
    
    > TestModel.new.save
    => true
  2. Transaction rollbacks - transactions handle ActiveRecord::Rollback by default, so the transaction block returns nil
    class TestModel
     def save
       result =
         ActiveRecord::Base.transaction do
           raise ActiveRecord::Rollback
         end
    
       result
     end
    end
    
    > TestModel.new.save
    => nil
  3. Other Errors - any errors raised inside the transaction will be raised by the block
    class TestModel
     def save
       result =
         ActiveRecord::Base.transaction do
           raise ActiveRecord::Rollback
         end
    
       result
     end
    end
    
    > TestModel.new.save
    StandardError: StandardError from .....

Putting it all together now, we can return a true/false for all scenarios -

class TestModel
    def save
      result =
        ActiveRecord::Base.transaction do
          SomeModel.new(attrs).save!
          OtherModel.new(other_attrs).save!
        end

      result

      did_save = !!result
      did_save
    rescue => e
       false
    end
end

Rails Generate Tasks

Andrew's TIL from the other day got me thinking about rails generators, and I never knew there was a generator for rake tasks!

There's not a ton of boilerplate in rake tasks, but that's never stopped me from making a typo.

bin/rails g task hello will generate just the namespace hello

# lib/tasks/hello.rake
namespace :hello do
end

If you have one or more tasks within the namespace, you can include them and the generator will add a task for each one:

bin/rails g task say hi bye good_day will generate

# lib/tasks/say.rake
namespace :say do
  desc "TODO"
  task hi: :environment do
  end

  desc "TODO"
  task bye: :environment do
  end

  desc "TODO"
  task good_day: :environment do
  end
end

Rails 8 Generate One Off Scripts

Rails 8 added a new generator command for creating 1 script files. The docs encourage the use of this folder for one off tasks, data migrations, etc. Previously, you could have used rake tasks to accomplish a similar thing.

Running this generator command will create the script dir if one does not already exist.

❯ rails g script migration_script
      create  script/migration_script.rb

Ruby 3.4 Warn on Method Unused Blocks

A change to Ruby 3.4 will print a warning while using the verbose flag -w when a method is passed a block and the block is not used by that method.

Here's our example file scratch.rb -

def print_message(message) = puts message

print_message("hello_world") { puts "hello anonymous" }
> ruby scratch.rb
hello world

> ruby -w scratch.rb
scratch.rb:3: warning: the block passed to 'Object#print_message' defined at scratch.rb:1 may be ignored
hello world

https://www.ruby-lang.org/en/news/2024/12/25/ruby-3-4-0-released/

Start a Rails Console in the Browser

When you generate a new Rails app, it comes with the web-console gem, a handy helper for embedding a rails console in the browser.

This can be useful in development for debugging things in the same process as your webserver. In my case, I used it to test out some action cable related things.

In your controller, just add console to the action -

class AppointmentsController < ApplicationController
  def index
    console
  end
end

image

https://github.com/rails/web-console

Ensure you're always using the same connection

In Rails, if you want to ensure that you are using the same database connection from the connection pool to execute a number of commands, you can use the ActiveRecord::Base.with_connection method.

This method yields a single connection from the pool for you to execute your commands against:

ActiveRecord::Base.with_connection do |conn|
  conn.execute("select * from sessions")
end

It is important to note that the connection yielded is taken out of the pool until the processing in the block is complete.

Convert a Keyword List to a Struct

You can use Kernel.struct/2 to convert a keyword list (or Enumerable) into a struct.

I found this useful when working with a new social media integration. I read some key-values out of the config environment and needed to convert these into a named struct.


> creds = Application.get_env(:tilex, __MODULE__)
[username: "foo", password: "bar"]

> struct(BlueskyEx.Client.Credentials, creds)
%BlueskyEx.Client.Credentials{
  username: "foo",
  password: "bar"
 }

When you pass keys that are not part of the struct, they are discarded for you. If you want to raise an error, you can use the related struct!/2 function

https://devdocs.io/elixir~1.17/kernel#struct/2

Vim Stores the Current Buffer's Path in a Register

Registers in (n)vim contain a lot of super useful data. To wit, the % register stores the path of the current buffer. Some useful things we can do with this register:

  • Write the path of the current buffer into the file in Insert Mode: Ctrl + R, %
  • If in Normal Mode: "%p
  • Copy the path to the clipboard: run the command "let @+=@% (copy the % buffer into the + buffer, which is usually used by the system clipboard), or echo it

ANSI Escape Codes

Today I learned that ANSI Escape Codes are a thing.

I was writing some Rails migrations and wanted nice readable output and a quick way to tell how things were going. So, I wanted some colored text to be displayed as output. This was how I learned about ANSI Escape Codes.

In short, you want to escape your string using \e then give it the prefix [ and then give it a series of codes to format your text.

For example, you can color all further text green using the code 32m or red using 31m.
If you want text to go back to normal give it the code 0m.

Here is an example: image

You can do other formatting than just color, but I found these to be helpful for what I needed and I didn't realize how simple it was.

FactoryBot Traits inside Traits

Today I learned you can nest FactoryBot traits within other traits. Traitception?!

Say you have a blog post model with a deleted_at attribute, and an optional deleted_by attribute. You could have:

FactoryBot.define do
  factory :post do
    trait :deleted do
      deleted_at { Time.current }
    end

    trait :deleted_by_admin do
      deleted
      deleted_by { :admin }
    end
  end
end

There the deleted in deleted_by_admin references the deleted trait above it.

You could alternatively define a new factory that composes the two traits, but it's always nice to have options.

factory :admin_deleted_post, traits: [:deleted, :deleted_by_admin]

Rails Environment Task

In a Rails task if you need to load in your rails application (to get access to your models, etc.), you have to call :environment in the task:

task task_name: :environment do 
  ...
end

I kind of always took this for granted, and never thought much about it. Then, in Xavier Noria's 2024 Rails World talk he mentioned that :environment itself is a task - and that syntax is actually saying your task depends upon :environment and run that task before your task runs. 🤯

So I decided to look up what the environment task actually does:

task :environment do
  ActiveSupport.on_load(:before_initialize) { config.eager_load = config.rake_eager_load }

  require_environment!
end

require_environment! ... requires your environment, specifically it requires your config/environment.rb which runs Rails.application.initialize! - which is what actually starts your rails app.

Cool!

RSpec expect not_to change from

I use the rspec change matcher a lot to check the before and after values of something while the subject under test executes. A convoluted example:

RSpec.describe "expect change from to" do
  it do
    x = 1
    expect{ x = x + 1 }.to change { x }.from(1).to(2)
  end
end

And sometimes I use to it to verify something doesn't change.

RSpec.describe "expect not to change" do
  it do
    x = 1
    expect{ nil }.not_to change { x }
  end
end

Which is great - but sometimes I want to make sure my understanding of the initial state is correct and want to verify it didn't change from its initial value - in this case 1.

RSpec.describe "expect not to change from" do
  it do
    x = 1
    expect{ nil }.not_to change { x }.from(1)
  end
end

And if that from value is wrong, I'll get a nice message explaining what's wrong.

RSpec.describe "expect not to change from" do
  it do
    x = 1
    expect{ nil }.not_to change { x }.from(0)
  end
end
# => expected `x` to have initially been 0, but was 1

Case Regex Matching with Capture Groups

I ran into a problem where I wanted to use a case statement to match against a regex, but also capture some values from the matched data.

Say I want to match on a pair of numbers wrapped in parens like (2,4) and add them together. If I match without capture groups I have to grab the numbers again in the when block:

x = "(2,4)"
case x
when /\(\d+,\d+\)/
  a,b = x.scan(/\d+/)
  a.to_i + b.to_i
end
# => 6

Seems a shame to have perform another op to get a and b. What if we used capturing groups like /\((\d+),\(d+)\)/? How do we refer to those captured values inside the when? We can use some of ruby's special variables, namely $1 and $2 to refer to the captured groups of the last regexp.

x = "(2,4)"
case x
when /\((\d+),(\d+)\)/
  $1.to_i + $2.to_i
end
# => 6

$1 and $2 feel a little magic, so we can name our capture groups group1 and group2, and access those from $~ (the MatchData of the last regexp).

x = "(2,4)"
case x
when /\((?<group1>\d+),(?<group2>\d+)\)/
  $~[:group1].to_i + $~[:group2].to_i
end
# => 6

Count Occurrences of Elements in List

The Enum Module in Elixir has the frequencies/1 function, which is useful for counting the occurrences of each element in a list.

> Enum.frequencies(["dog", "cat", "dog", "bird", "dog", "cat"])
%{"bird" => 1, "cat" => 2, "dog" => 3}

There's also frequencies_by/2, where the 2nd argument is a function that normalizes the element/key before counting.

> Enum.frequencies_by(["a", "b", "a", "C", "A"], fn key ->
  String.upcase(key)
end)
%{"A" => 3, "B" => 1, "C" => 1}

https://devdocs.io/elixir~1.17/enum#frequencies/1

Break words in Tailwind.

In Tailwind you can use certain classes to wrap text within an element.
You could use something like text-wrap or whitespace-pre-wrap, or any of the other classes.

However, if a single word is too long it will continue on past the element it is contained in.

Kind of like this:

<div class="text-wrap">
<!-- really long text -->
</div>

HEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGword

Well, just add the Tailwind class break-words and it will break up a word when it reaches the end of the element, and you'll get something more like this:

<div class="text-wrap break-words">
<!-- really long text -->
</div>

HEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGword HEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGwordHEREisAreallyLONGword

Generate Rails Models with Namespaces

You can use the rails model generator to generate namespaced models. I always have a hard time remembering the syntax for namespaces, but it's pretty straightforward.

Say I want to create a model Blog::Post. The generator for this is:

rails generate model blog/post title:string ...

This will generate the following files (assuming you're using rspec and FactoryBot)

invoke  active_record
create    db/migrate/20241028193321_create_blog_posts.rb
create    app/models/blog/post.rb
create    app/models/blog.rb
invoke    rspec
create      spec/models/blog/post_spec.rb
invoke      factory_bot
create        spec/factories/blog/posts.rb

If the namespace already exists, you'll be prompted to either overwrite or keep the existing app/models/blog.rb file (you'll probably want to keep the existing one).

Happy generating!

Expo Reactive Native Apps on IOS Simulator

With Expo's CLI, the command npx expo run:ios will build and run your application in xcode's IOS simulator. You will need to have Xcode installed in order for the command to work. If you receive an error stating Xcode must be fully installed before you can continue, you may need to navigate to Xcode's settings and set a version of command line tools under the locations tab. image

Create index with migration shorthand in Rails

Using the Ruby on Rails migration generator is great to get up and running but always seems to require just a little bit more effort once the migration file is created.

There is a shorthand syntax for the cli interface of the generator but I can never remember it past a column name and type... so I'm putting this here to remember it for all of us!

To create an index just continue adding a bit more information to your column declaration. Let's start with this as a base so we're on the same page:

rails generate add_name_to_widgets name

This will create this migration:

class AddNameToWidgets < ActiveRecord::Migration[7.0]
  def change
    add_column :widgets, :name, :string
  end
end

Now by making a minor adjustment to the original cli call we can generate the index too:

rails generate add_name_to_widgets name:string:index
class AddNameToWidgets < ActiveRecord::Migration[7.0]
  def change
    add_column :widgets, :name, :string
    add_index :widgets, :name
  end
end

And you know what? We can do unique indexes as well:

rails generate add_name_to_widgets name:string:uniq
class AddNameToWidgets < ActiveRecord::Migration[7.0]
  def change
    add_column :widgets, :name, :string
    add_index :widgets, :name, unique: true
  end
end

Generate non-null field migration in Rails 8

I'm sure many of us are familiar with the Ruby on Rails migration generator...

rails generate migration add_name_to_widgets name

which generates a migration that looks like so:

class AddNameToWidgets < ActiveRecord::Migration[7.0]
  def change
    add_column :widgets, :name, :string
  end
end

Then to make the name column have a non-null constraint an addition of null: false would be needed:

class AddNameToWidgets < ActiveRecord::Migration[7.0]
  def change
    add_column :widgets, :name, :string, null: false
  end
end

However, now in Rails 8 an adjustment was made to allow this to be done from the generator shorthand

rails generate migration add_name_to_widgets name:string!

By adding the exclamation point after the column type a migration will now be generated as we wanted before but without the additional manual edit:

class AddNameToWidgets < ActiveRecord::Migration[8.0]
  def change
    add_column :widgets, :name, :string, null: false
  end
end

h/t Akshay Khot

PG Cluster Commands in Ubuntu

The postgresql package for Ubuntu includes some useful commands for managing your database cluster. I learned about these today when we upgraded postgres versions on a digital ocean droplet.

The ones that I learned of were -

  • pg_lsclusters for listing the available clusters on the machine and their status
  • pg_upgradecluster OLD_VERSION CLUSTER_NAME for upgrading to a new cluster. If you don't specify the optional -v (new version), it's assumed you want the most recent version you have installed. This handles copying your old conf files to the new version and setting it up on the originally specified port.
  • pg_dropcluster VERSION CLUSTER_NAME for removing a cluster. Optionally you can specify --stop to force a shutdown and delete.
  • pg_createcluster VERSION CLUSTER_NAME which will create a new cluster given the version and name param. The default is to not start this new cluster on creation, but you can optionally specify the --start flag to immediately start the cluster.

https://manpages.ubuntu.com/manpages/trusty/man8/pg_createcluster.8.html https://manpages.ubuntu.com/manpages/trusty/en/man8/pg_dropcluster.8.html https://manpages.ubuntu.com/manpages/trusty/man8/pg_upgradecluster.8.html https://manpages.ubuntu.com/manpages/xenial/en/man1/pg_lsclusters.1.html

String Replace in Javascript

I'm very used to ruby's gsub(pattern, replacement) that does a [g]lobal [sub]stitution on a string - that is, it replaces all occurrences of the pattern in the string. If you wanted to just replace the first occurrence of the pattern you could use sub, but I so rarely need to do that I forgot it existed.

Javascript's equivalent, replace, handles things a little bit differently. So much so I was surprised by it's behavior.

replace(pattern, replacement)

pattern can be a string or a RegExp, but you get different replacement behavior depending on which you use.

  • If pattern is a string, only the first occurrence of pattern will be replaced.
  • If pattern is a RegExp, by default it will replace the first occurrence, unless you pass the global flag to the pattern. So if I wanted to replace asdf in with hjkl in a string, replace(/asdf/, "hjkl") will replace just the first occurrence. To replace all occurrences, it needs to be replace(/adsf/g, "hjkl) (note the global g flag in the regex).

So maybe the moral of the story is to always use a regex (and remember your flags!).

Docs: String.prototype.replace() - JavaScript | MDN

Sigils in Elixir

In Elixir, there's strings "hi" and charlists 'hi'.

You can also use the ~c sigil to denote a charlist -

~c"hi there"

There's also a word list sigil ~w which behaves similarly to %w in Ruby. It constructs a list of words -

~w(blue red green)
=> ["blue", "red", "green"]

Also worth mentioning, the ~r sigil for regexes -

"foo" =~ ~r"hashrocket"
=> false

"hashrocket" =~ ~r/hashrocket/
=> true

There's many other sigils in Phoenix and Elixir. Be sure to check out the docs!

h/t to Jack Rosa

https://hexdocs.pm/elixir/sigils.html

Alias Method on a GraphQL Field

A lot of times I find I have to alias a method on a model when I'm exposing it on a GraphQL type. Most often I have to do this with ? methods:

class Post < ApplicationRecord
  def draft?
    ...
  end
end

class PostType < GraphQL::Schema::Object
  field :draft, Boolean, null: false

  def draft
    @object.draft?
  end
end

I want the field to be draft (without the ?), but on it's own the GraphQL Ruby gem can't resolve it to draft?, so I have to add an additional def in the Type class. This works, but it feels clunky.

Turns out you can use the method: option on the field to alias it inline, which I think streamlines things:

class PostType < GraphQL::Schema::Object
  field :draft, Boolean, null: false, method: :draft?
end

Docs

Refetch Query with Apollo GraphQL Client

The Apollo GraphQL client allows you to easily refetch query results, which can come in super handy if you need to refresh data after some user action on the page. You can do this with the refetch function from useQuery:

const { data, loading, refetch } = useQuery(QUERY);

Then if you want to refetch data after a button click, you can:

<button onClick={() => refetch()}>
  Refetch the data!!
</button>

If you defined any variables in the initial useQuery, refetching will re-use those variables, but you can override them as well in the call to refetch:

refetch({ param: "new value" });

If you need to refetch data after a mutation, you can do that too.

Docs

Change Text of Blank Option in a Rails Select Tag

The form helper select tag (ex - f.select) accepts a boolean option for include_blank, which informs the select tag to have an extra blank option. Setting include_blank: true will look like the below - image

But you can also pass a string to include_blank and this will change the text content of the blank option -

<%= f.select :state, options_for_select(state_options), {include_blank: 'Select a State'} %>

image

https://devdocs.io/rails~7.1/actionview/helpers/formtaghelper#method-i-select_tag

casecmp to Compare Strings

Today I learned about casecmp and casecmp? to compare strings in ruby.

casecmp compares the downcase of both strings and returns 1 if the compared string is smaller, -1 if it's larger, and 0 if they are equal (and nil if they can't be compared).

"hashrocket".casecmp("hashrocket") # => 0
"hashrocket".casecmp("hAsHrOcKeT") # => 0
"hashrocket".casecmp("hashrocket123") # => -1
"hashrocket".casecmp("hashrock") # => 1
"hashrocket".casecmp(123) # => nil

casecmp? does the same comparison but just returns a boolean.

"hashrocket".casecmp("hAsHrOcKeT") # => true
"hashrocket".casecmp("hashrock") # => false
"hashrocket".casecmp(123) # => nil

h/t Brian Dunn

Enum Reject vs Filter

If you're anything like me, you regularly forget if Enum.filter/2 keeps elements that return true or filters them out.

Let existence of Enum.reject/2 be your reminder.

reject/2 does the same thing as filter/2 but discards truthy elements instead of keeping them. I wish that filter/2 was renamed to keep/2, then the 2 functions would feel more like logical opposites and perhaps more readable.

Ruby GraphQL Generators

Today I Learned the GraphQL ruby gem includes generators for types, mutations and other fun things.

rails g graphql:object
rails g graphql:input
rails g graphql:interface
rails g graphql:union
rails g graphql:enum
rails g graphql:scalar
rails g graphql:mutation

What's even neater is if the name of thing things you're generating matches an existing ActiveRecord model, it will scaffold all the database columns as fields!

If you have a model Book like:

class Book < ApplicationRecord
  attribute :id
  attribute :author_id
  attribute :title
  attribute :published_at
end

Running the object generator rails g graphql:object Book will produce:

module Types
  class BookType < Types::BaseObject
    field :id, ID
    field :author_id, ID
    field :title, String
    field :published_at, GraphQL::Types::ISO8601DateTime
  end
end