mirror of
https://github.com/jbranchaud/til
synced 2026-01-20 07:28:02 +00:00
Compare commits
1 Commits
c843bbcda9
...
e8580e82ef
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8580e82ef |
@@ -10,7 +10,7 @@ pairing with smart people at Hashrocket.
|
|||||||
|
|
||||||
For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186).
|
For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186).
|
||||||
|
|
||||||
_1576 TILs and counting..._
|
_1569 TILs and counting..._
|
||||||
|
|
||||||
See some of the other learning resources I work on:
|
See some of the other learning resources I work on:
|
||||||
- [Ruby Operator Lookup](https://www.visualmode.dev/ruby-operators)
|
- [Ruby Operator Lookup](https://www.visualmode.dev/ruby-operators)
|
||||||
@@ -199,15 +199,12 @@ See some of the other learning resources I work on:
|
|||||||
- [Check The Status of All Services](devops/check-the-status-of-all-services.md)
|
- [Check The Status of All Services](devops/check-the-status-of-all-services.md)
|
||||||
- [Check The Syntax Of nginx Files](devops/check-the-syntax-of-nginx-files.md)
|
- [Check The Syntax Of nginx Files](devops/check-the-syntax-of-nginx-files.md)
|
||||||
- [Connect To An RDS PostgreSQL Database](devops/connect-to-an-rds-postgresql-database.md)
|
- [Connect To An RDS PostgreSQL Database](devops/connect-to-an-rds-postgresql-database.md)
|
||||||
- [Default Rails Deploy Script On Hatchbox](devops/default-rails-deploy-script-on-hatchbox.md)
|
|
||||||
- [Determine The IP Address Of A Domain](devops/determine-the-ip-address-of-a-domain.md)
|
- [Determine The IP Address Of A Domain](devops/determine-the-ip-address-of-a-domain.md)
|
||||||
- [Hatchbox Exports Env Vars With asdf](devops/hatchbox-exports-env-vars-with-asdf.md)
|
|
||||||
- [Path Of The Packets](devops/path-of-the-packets.md)
|
- [Path Of The Packets](devops/path-of-the-packets.md)
|
||||||
- [Push Non-master Branch To Heroku](devops/push-non-master-branch-to-heroku.md)
|
- [Push Non-master Branch To Heroku](devops/push-non-master-branch-to-heroku.md)
|
||||||
- [Reload The nginx Configuration](devops/reload-the-nginx-configuration.md)
|
- [Reload The nginx Configuration](devops/reload-the-nginx-configuration.md)
|
||||||
- [Resolve The Public IP Of A URL](devops/resolve-the-public-ip-of-a-url.md)
|
- [Resolve The Public IP Of A URL](devops/resolve-the-public-ip-of-a-url.md)
|
||||||
- [Running Out Of inode Space](devops/running-out-of-inode-space.md)
|
- [Running Out Of inode Space](devops/running-out-of-inode-space.md)
|
||||||
- [Set Up Domain For Hatchbox Rails App](devops/set-up-domain-for-hatchbox-rails-app.md)
|
|
||||||
- [SSH Into A Docker Container](devops/ssh-into-a-docker-container.md)
|
- [SSH Into A Docker Container](devops/ssh-into-a-docker-container.md)
|
||||||
- [SSL Certificates Can Cover Multiple Domains](devops/ssl-certificates-can-cover-multiple-domains.md)
|
- [SSL Certificates Can Cover Multiple Domains](devops/ssl-certificates-can-cover-multiple-domains.md)
|
||||||
- [Wipe A Heroku Postgres Database](devops/wipe-a-heroku-postgres-database.md)
|
- [Wipe A Heroku Postgres Database](devops/wipe-a-heroku-postgres-database.md)
|
||||||
@@ -781,7 +778,6 @@ See some of the other learning resources I work on:
|
|||||||
- [Convert A String To A Timestamp](postgres/convert-a-string-to-a-timestamp.md)
|
- [Convert A String To A Timestamp](postgres/convert-a-string-to-a-timestamp.md)
|
||||||
- [Count How Many Records There Are Of Each Type](postgres/count-how-many-records-there-are-of-each-type.md)
|
- [Count How Many Records There Are Of Each Type](postgres/count-how-many-records-there-are-of-each-type.md)
|
||||||
- [Count Records By Type](postgres/count-records-by-type.md)
|
- [Count Records By Type](postgres/count-records-by-type.md)
|
||||||
- [Count The Number Of Items In An Array](postgres/count-the-number-of-items-in-an-array.md)
|
|
||||||
- [Count The Number Of Trues In An Aggregate Query](postgres/count-the-number-of-trues-in-an-aggregate-query.md)
|
- [Count The Number Of Trues In An Aggregate Query](postgres/count-the-number-of-trues-in-an-aggregate-query.md)
|
||||||
- [Create A Cluster In A Specific Data Directory](postgres/create-a-cluster-in-a-specific-data-directory.md)
|
- [Create A Cluster In A Specific Data Directory](postgres/create-a-cluster-in-a-specific-data-directory.md)
|
||||||
- [Create A Composite Primary Key](postgres/create-a-composite-primary-key.md)
|
- [Create A Composite Primary Key](postgres/create-a-composite-primary-key.md)
|
||||||
@@ -957,7 +953,6 @@ See some of the other learning resources I work on:
|
|||||||
- [All or Nothing Database Transactions](rails/all-or-nothing-database-transactions.md)
|
- [All or Nothing Database Transactions](rails/all-or-nothing-database-transactions.md)
|
||||||
- [Alphabetize Schema Columns To Keep Them Consistent](rails/alphabetize-schema-columns-to-keep-them-consistent.md)
|
- [Alphabetize Schema Columns To Keep Them Consistent](rails/alphabetize-schema-columns-to-keep-them-consistent.md)
|
||||||
- [Alter The Rails Setup Script](rails/alter-the-rails-setup-script.md)
|
- [Alter The Rails Setup Script](rails/alter-the-rails-setup-script.md)
|
||||||
- [Apply Basic HTML Formatting To Block Of Text](rails/apply-basic-html-formatting-to-block-of-text.md)
|
|
||||||
- [Assert Two Arrays Have The Same Items With RSpec](rails/assert-two-arrays-have-the-same-items-with-rspec.md)
|
- [Assert Two Arrays Have The Same Items With RSpec](rails/assert-two-arrays-have-the-same-items-with-rspec.md)
|
||||||
- [Attach A File With Capybara](rails/attach-a-file-with-capybara.md)
|
- [Attach A File With Capybara](rails/attach-a-file-with-capybara.md)
|
||||||
- [Attribute Getter without the Recursion](rails/attribute-getter-without-the-recursion.md)
|
- [Attribute Getter without the Recursion](rails/attribute-getter-without-the-recursion.md)
|
||||||
@@ -1034,7 +1029,6 @@ See some of the other learning resources I work on:
|
|||||||
- [Migrating Up Down Up](rails/migrating-up-down-up.md)
|
- [Migrating Up Down Up](rails/migrating-up-down-up.md)
|
||||||
- [Mock Rails Environment With An Inquiry Instance](rails/mock-rails-environment-with-an-inquiry-instance.md)
|
- [Mock Rails Environment With An Inquiry Instance](rails/mock-rails-environment-with-an-inquiry-instance.md)
|
||||||
- [Order Matters For `rescue_from` Blocks](rails/order-matters-for-rescue-from-blocks.md)
|
- [Order Matters For `rescue_from` Blocks](rails/order-matters-for-rescue-from-blocks.md)
|
||||||
- [Override Text Displayed By Form Label](rails/override-text-displayed-by-form-label.md)
|
|
||||||
- [Params Includes Submission Button Info](rails/params-includes-submission-button-info.md)
|
- [Params Includes Submission Button Info](rails/params-includes-submission-button-info.md)
|
||||||
- [Params Is A Hash With Indifferent Access](rails/params-is-a-hash-with-indifferent-access.md)
|
- [Params Is A Hash With Indifferent Access](rails/params-is-a-hash-with-indifferent-access.md)
|
||||||
- [Parse Query Params From A URL](rails/parse-query-params-from-a-url.md)
|
- [Parse Query Params From A URL](rails/parse-query-params-from-a-url.md)
|
||||||
@@ -1830,7 +1824,6 @@ See some of the other learning resources I work on:
|
|||||||
- [Rotate An Image To Be Oriented Upright](workflow/rotate-an-image-to-be-oriented-upright.md)
|
- [Rotate An Image To Be Oriented Upright](workflow/rotate-an-image-to-be-oriented-upright.md)
|
||||||
- [See Overlaps For A Set Of Time Zones](workflow/see-overlaps-for-a-set-of-time-zones.md)
|
- [See Overlaps For A Set Of Time Zones](workflow/see-overlaps-for-a-set-of-time-zones.md)
|
||||||
- [Send A Message To A Discord Channel](workflow/send-a-message-to-a-discord-channel.md)
|
- [Send A Message To A Discord Channel](workflow/send-a-message-to-a-discord-channel.md)
|
||||||
- [Send A PDF To Your Kindle](workflow/send-a-pdf-to-your-kindle.md)
|
|
||||||
- [Set Recurring Reminders In Slack](workflow/set-recurring-reminders-in-slack.md)
|
- [Set Recurring Reminders In Slack](workflow/set-recurring-reminders-in-slack.md)
|
||||||
- [Show Linting Errors In Zed](workflow/show-linting-errors-in-zed.md)
|
- [Show Linting Errors In Zed](workflow/show-linting-errors-in-zed.md)
|
||||||
- [Temporarily Hide CleanShot X Capture Previews](workflow/temporarily-hide-cleanshot-x-capture-previews.md)
|
- [Temporarily Hide CleanShot X Capture Previews](workflow/temporarily-hide-cleanshot-x-capture-previews.md)
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
# Default Rails Deploy Script On Hatchbox
|
|
||||||
|
|
||||||
I deployed a Rails app to [Hatchbox](https://hatchbox.io) recently. When
|
|
||||||
following along in the log during a deploy, I can see most of what is happening
|
|
||||||
as part of the deploy. Though it is too verbose to look through every line. I'd
|
|
||||||
rather see the contents of the deploy script.
|
|
||||||
|
|
||||||
I did quite a bit of digging around while SSH'd into my hatchbox server, but I
|
|
||||||
couldn't find if or where that file might be stored.
|
|
||||||
|
|
||||||
Instead, there is a [_Help Center_
|
|
||||||
article](https://hatchbox.relationkit.io/articles/55-what-is-the-default-rails-deploy-script)
|
|
||||||
where Chris Oliver shares what is in the script.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bundle install -j $(nproc)
|
|
||||||
yarn install
|
|
||||||
bundle exec rails assets:precompile
|
|
||||||
[[ -n "${CRON}" ]] && bundle exec rails db:migrate
|
|
||||||
```
|
|
||||||
|
|
||||||
It does a parallelized `bundle install`, then a `yarn install` (make sure your
|
|
||||||
project is using `yarn.lock`), Rails asset precompilation, and then if `CRON`
|
|
||||||
is set (Cron role is available by checking _Cron_ under _Server
|
|
||||||
Responsibilities_ for your Hatchbox server), it will run Rails migrations.
|
|
||||||
|
|
||||||
From app settings, the deploy script can be overridden, or pre- and post-deploy
|
|
||||||
steps can be added.
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# Hatchbox Exports Env Vars With asdf
|
|
||||||
|
|
||||||
When you add env vars through the [Hatchbox](https://hatchbox.io/) UI, they get
|
|
||||||
exported to the environment of the asdf-shimmed processes. This is handled by
|
|
||||||
the [`asdf-vars` plugin](https://github.com/excid3/asdf-vars). That plugin
|
|
||||||
looks for `.asdf-vars` in the current chain of directories.
|
|
||||||
|
|
||||||
I can see there are many `.asdf-vars` files:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ find . -name ".asdf-vars" -type f
|
|
||||||
./.asdf-vars
|
|
||||||
./my-app/.asdf-vars
|
|
||||||
./my-app/releases/20250120195106/.asdf-vars
|
|
||||||
./my-app/releases/20250121041054/.asdf-vars
|
|
||||||
```
|
|
||||||
|
|
||||||
And it is the one in my app's directory that contains the env vars that I set
|
|
||||||
in the UI.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ cat my-app/.asdf-vars
|
|
||||||
BUNDLE_WITHOUT=development:test
|
|
||||||
DATABASE_URL=postgresql://user_123:123456789012345@10.0.1.1/my_app_db
|
|
||||||
PORT=9000
|
|
||||||
RACK_ENV=production
|
|
||||||
RAILS_ENV=production
|
|
||||||
RAILS_LOG_TO_STDOUT=true
|
|
||||||
RAILS_MASTER_KEY=abc123
|
|
||||||
SECRET_KEY_BASE=abc123efg456
|
|
||||||
```
|
|
||||||
|
|
||||||
When I run a shimmed process like `ruby`, those env vars are loaded into the
|
|
||||||
process's environment.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ cd my-app/current
|
|
||||||
$ which ruby
|
|
||||||
/home/deploy/.asdf/shims/ruby
|
|
||||||
$ ruby -e "puts ENV['DATABASE_URL']"
|
|
||||||
postgresql://user_123:123456789012345@10.0.1.1/my_app_db
|
|
||||||
```
|
|
||||||
|
|
||||||
[source](https://www.visualmode.dev/hatchbox-manages-env-vars-with-asdf)
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# Set Up Domain For Hatchbox Rails App
|
|
||||||
|
|
||||||
When we deploy a Rails app with [Hatchbox](https://hatchbox.io), we are given
|
|
||||||
an internal URL for publicly accessing our app. It is something like
|
|
||||||
`https://123abc.hatchboxapp.com`. That's useful as we are getting things up and
|
|
||||||
running, but eventually we want to point our own domain at the app.
|
|
||||||
|
|
||||||
The first step is to tell Hatchbox what domain we are going to use.
|
|
||||||
|
|
||||||
From our app's _Domain & SSL_ page we can enter a domain into the _Add A
|
|
||||||
Domain_ input. For instance, I have the
|
|
||||||
[visualmode.dev](https://visualmode.dev) domain and I want the
|
|
||||||
[still.visualmode.dev](https://still.visualmode.dev) subdomain pointing at my
|
|
||||||
Rails app. I submit the full name `still.visualmode.dev` and I get an _A
|
|
||||||
Record_ ipv4 address (e.g. `23.12.234.82`).
|
|
||||||
|
|
||||||
The second step is to configure a DNS record with our domain registrar.
|
|
||||||
|
|
||||||
From the DNS settings of our registrar (e.g. Cloudflare) we can add an _A
|
|
||||||
Record_ where we specify the name (e.g. `still`) and then include the ipv4
|
|
||||||
address provided by Hatchbox. We can save this and wait a minute for it to
|
|
||||||
propagate.
|
|
||||||
|
|
||||||
And soon enough we can visit our Rails app at the custom domain.
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
# Count The Number Of Items In An Array
|
|
||||||
|
|
||||||
There are two ways to count the number of items in an array with PostgreSQL.
|
|
||||||
The one that might jump out at you or show up at the top of search results is
|
|
||||||
[`array_length`](https://www.postgresql.org/docs/current/functions-array.html).
|
|
||||||
|
|
||||||
```sql
|
|
||||||
> select array_length(array[1,2,3], 1);
|
|
||||||
+--------------+
|
|
||||||
| array_length |
|
|
||||||
|--------------|
|
|
||||||
| 3 |
|
|
||||||
+--------------+
|
|
||||||
|
|
||||||
> select array_length(array[[1,2], [3,4]], 2);
|
|
||||||
+--------------+
|
|
||||||
| array_length |
|
|
||||||
|--------------|
|
|
||||||
| 2 |
|
|
||||||
+--------------+
|
|
||||||
```
|
|
||||||
|
|
||||||
This requires specifying the dimension at which you want to check the length.
|
|
||||||
The first example, checking the 1st dimension of a one-dimensional array, seems
|
|
||||||
like the more common and useful scenario. In the second example, we are
|
|
||||||
checking the 2nd dimension.
|
|
||||||
|
|
||||||
The other way we can determine the number of items in an array is with the
|
|
||||||
[`cardinality`](https://www.postgresql.org/docs/current/functions-array.html)
|
|
||||||
function.
|
|
||||||
|
|
||||||
> Returns the total number of elements in the array, or 0 if the array is
|
|
||||||
> empty.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
> select cardinality(array[1,2,3]);
|
|
||||||
+-------------+
|
|
||||||
| cardinality |
|
|
||||||
|-------------|
|
|
||||||
| 3 |
|
|
||||||
+-------------+
|
|
||||||
|
|
||||||
> select cardinality(array[[1,2], [3,4]]);
|
|
||||||
+-------------+
|
|
||||||
| cardinality |
|
|
||||||
|-------------|
|
|
||||||
| 4 |
|
|
||||||
+-------------+
|
|
||||||
```
|
|
||||||
|
|
||||||
This behaves the same as `array_length` for a one-dimensional array and doesn't
|
|
||||||
require a second argument. Where it gets more interesting is with
|
|
||||||
multi-dimensional arrays. It returns the total number of elements in the
|
|
||||||
arrayregardless of the nesting.
|
|
||||||
|
|
||||||
[source](https://mattrighetti.com/2025/01/20/you-dont-need-sql-builders)
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
# Apply Basic HTML Formatting To Block Of Text
|
|
||||||
|
|
||||||
My Rails app has a form that allows a user to enter in free-form text. I enter
|
|
||||||
in a couple paragraphs and save the record. It is rendered on a show page with
|
|
||||||
a couple lines of ERB like so:
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
<div class="max-w-3xl mx-auto">
|
|
||||||
<div class="space-y-4">
|
|
||||||
<div class="prose mt-8 text-gray-700">
|
|
||||||
<%= @record.notes %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
When I view the erb-displayed version of that record's text, all those
|
|
||||||
carefully spaced paragraphs are clumped together. That is because those newline
|
|
||||||
(`\n` and `\n\n`) characters while understood to be whitespace do not have
|
|
||||||
formatting implications in the browser like a combination of HTML tags and CSS
|
|
||||||
do.
|
|
||||||
|
|
||||||
I can apply some basic formatting with [the aptly named `simple_format` method
|
|
||||||
available as an `ActionView`
|
|
||||||
helper](https://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-simple_format).
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
<div class="max-w-3xl mx-auto">
|
|
||||||
<div class="space-y-4">
|
|
||||||
<div class="prose mt-8 text-gray-700">
|
|
||||||
<%= simple_format(@record.notes) %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
This turns single `\n` characters into a `<br />` tag and double `\n\n` cause
|
|
||||||
the surrounding paragraphs to be wrapped in `<p>` tags. That simple formatting
|
|
||||||
combined with my existing TailwindCSS styles makes the formatting of my text
|
|
||||||
immediately look much better.
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
# Override Text Displayed By Form Label
|
|
||||||
|
|
||||||
Rails does a good job with the default text displayed by a form label. It takes
|
|
||||||
the primary symbol value you give it and capitalizes that. And that is often
|
|
||||||
good enough.
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
<%= form_with(model: post) do |form| %>
|
|
||||||
<%= form.label :title, class: "text-sm font-medium text-gray-700" %>
|
|
||||||
<%= form.text_field :title, required: true, class: "..." %>
|
|
||||||
<% end %>
|
|
||||||
```
|
|
||||||
|
|
||||||
This will yield a label value of _Title_.
|
|
||||||
|
|
||||||
Sometimes, however, the casing needs to be different or you need entirely
|
|
||||||
different text. Take this URL field for example. Rails will convert `:url` into
|
|
||||||
_Url_ for the label text. Not ideal. I can override the default with a second
|
|
||||||
positional argument, in this case, `"URL"`.
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
<%= form_with(model: post) do |form| %>
|
|
||||||
<%= form.label :url, "URL", class: "text-sm font-medium text-gray-700" %>
|
|
||||||
<%= form.url_field :url, required: true, class: "..." %>
|
|
||||||
<% end %>
|
|
||||||
```
|
|
||||||
|
|
||||||
The [Rails docs have another good
|
|
||||||
example](https://guides.rubyonrails.org/form_helpers.html#a-generic-search-form).
|
|
||||||
A label with a value of `query` that is overridden to display "Search for:".
|
|
||||||
|
|
||||||
```ruby
|
|
||||||
<%= form_with url: "/search", method: :get do |form| %>
|
|
||||||
<%= form.label :query, "Search for:" %>
|
|
||||||
<%= form.search_field :query %>
|
|
||||||
<%= form.submit "Search" %>
|
|
||||||
<% end %>
|
|
||||||
```
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# Send A PDF To Your Kindle
|
|
||||||
|
|
||||||
I recently got a Kindle. I already have a bunch of PDF and ePub books on my
|
|
||||||
computer that I've bought over the years. I wanted to be able to read some of
|
|
||||||
those books on the Kindle. I found that there is a way to send these formats to
|
|
||||||
your Kindle via email.
|
|
||||||
|
|
||||||
There are a couple steps to get this working.
|
|
||||||
|
|
||||||
First, from the Amazon account that is tied to the Kindle device, open the
|
|
||||||
_Account_ dropdown and click _Devices. Any devices tied to your account will be
|
|
||||||
listed there. Navigate to the one you want to send to. Under the _Device
|
|
||||||
Summary_ with be a custom email address for that device. Something like
|
|
||||||
`youremail_abc123@kindle.com`.
|
|
||||||
|
|
||||||
That's the email you'll send the PDF or ePub attachment to.
|
|
||||||
|
|
||||||
Second, that Kindle email address will only receive and process documents from
|
|
||||||
a known, verified email address. Back on the _Devices_page, click on the
|
|
||||||
_Preferences_ tab. Under _Personal Document Preferences_ make sure that the
|
|
||||||
_Approved Personal Document Email List_ includes the email address you'll be
|
|
||||||
sending from. Add it if not.
|
|
||||||
|
|
||||||
Everything is set up. Now compose an email to that Kindle address, add the
|
|
||||||
attachment, and send. Give it 5 or so minutes to process and it should show up
|
|
||||||
on your device.
|
|
||||||
|
|
||||||
Additionally, you can go to the _Content_ tab and then to _Digital Content_ to
|
|
||||||
see what documents you have set and which devices have received them.
|
|
||||||
|
|
||||||
[source](https://goodereader.com/blog/kindle/here-is-how-you-can-read-pdf-files-on-the-amazon-kindle)
|
|
||||||
Reference in New Issue
Block a user