Show Keyboard in Xcode Simulator
If you want to see the device keyboard while using the Xcode simulator, use β + K
If you want to see the device keyboard while using the Xcode simulator, use β + K
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
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!
I sometimes press the r
key on accident when in netrw. This toggles the sort direction of the files and folders. You can hit it one more time to change it back to default.
You can also try sorting by different parameters with the s
key - name, file type, or file size.
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.
If you want to see the file sizes for Folders and not just files, press CMD+J
in Finder and then make sure Calculate all sizes
is checked and then hit Use as defaults
to save this as the default setting.
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
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
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
File.stat/2
will return data from the path passed to it, including the accessed time atime
and the modified time mtime
.
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.
pattern
is a string, only the first occurrence of pattern
will be replaced. 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!).
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
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
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.
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 -
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'} %>
https://devdocs.io/rails~7.1/actionview/helpers/formtaghelper#method-i-select_tag
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
Today I learned you can view all the highlight groups currently set in (neo)vim by running :highlight
. With that you can see what the syntax highlighting looks like and how it's defined in terms of color codes or links to another group.
In a Sentry session replay, you can view if a user rage clicks on an element in your app. A rage click is defined as "a series of rapid clicks on the same unresponsive element".
Similarly, sentry records "Dead" clicks when a user clicks on an element and the page does not visibly respond within 7000ms.
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.
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
If you pass the -p
option to mkdir, it will create any necessary parent directories that do not exist yet. In Elixir the File.mkdir_p/1
function will do the same thing!
You can sort an enum by multiple keys at once. For example, If we wanted to sort a list of 'Vehicle' structs by type and model at the same time, we could do this:
vehicle_list = [
%Vehicle{type: "van", model: "Odyssey"},
%Vehicle{type: "truck", model: "Avalanche"},
%Vehicle{type: "van", model: "Pacifica"},
%Vehicle{type: "truck", model: "Bronco"}
]
Enum.sort_by(vehicle_list, &{&1.type, &1.model})
#=>
[
%Vehicle{type: "truck", model: "Avalanche"},
%Vehicle{type: "truck", model: "Bronco"},
%Vehicle{type: "van", model: "Odyssey"},
%Vehicle{type: "van", model: "Pacifica"},
]
sort_by
is first sorting the vehicles by the :type
key and then sorting by the :model
key.
Today I learned about some nice helper methods for ActiveRecord Enums. You might already know the ?
methods to check the value of the enum. There are also !
methods to succinctly set the value of the enum too!
class Post < ActiveRecord::Base
enum status: {
draft: 0,
published: 1
}
end
post = Post.new
post.published? # => false
post.published! # updates the status to `published`
post.published? # => true
In an Ecto query expression, use distinct: true
to ensure the values returned from your query are distinct.
from(u in User, distinct: true, select: u.first_name)
You can also use distinct with an expression to be more specific
from(u in User,
distinct: last_name,
order_by: [asc: :last_name])
With Finder open, you can press cmd β
+ option β₯
+ p
to toggle the filepath bar at the bottom of the window.
When I'm writing longer form text in vim, I like to turn on spell
check. I don't
always want spell check on, so I toggle it on manually when I'm in a Markdown or
text file: :set spell
.
While I always remember how to toggle it on, I never remember how to toggle it off:
:set nospell
It's the same syntax for any setting - if you wanted to turn off incsearch
,
its :set noincsearch
.
git checkout -
takes you right back to the previously checked out branch.
In Rails, there is an nice and easy interface that can be used to check a string for equality.
To do this, you can use the ActiveSupport::StringInquirer
object. Simply initialize it with a string value, like so:
string = ActiveSupport::StringInquirer.new("vanilla")
and now we can just call string#vanilla?
to check for equality
string.vanilla?
=> true
string.chocolate?
=> false
Fun fact:
This is how you are able to do Rails.env.production?
H/T: Matt Polito
As a follow up to my previous TIL about building expo, I just learned that you can run your build locally! Just use the --local
flag.
It's important to note, you will need Ruby installed locally, as well as the fastlane
and cocoapods
gems
gem install fastlane cocoapods # only if you haven't already
eas build --platform ios --profile dev --local
If you enter time
before any terminal command, it will output some information about how long the task took to run.
For example, let's run it on these two, crude, simple ruby scripts to see the time difference
# ./million.rb
1_000_000.times do
2 + 2
end
> time ruby million.rb
ruby million.rb 0.05s user 0.02s system 47% cpu 0.143 total
β
# ./billion.rb
1_000_000_000.times do
2 + 2
end
> time ruby billion.rb
ruby billion.rb 18.41s user 0.13s system 99% cpu 18.618 total
H/T Matt Polito
You can stub environment variables in Vitest using vi.stubEnv
. This will stub the value on process.env
and import.meta.env
.
You can also reset all env vars back to their original value with vi.unstubAllEnvs
.
process.env.COOL_ENV_VAR; // => "test"
import.meta.env.COOL_ENV_VAR; // => "test"
vi.stubEnv('COOL_ENV_VAR', "stubbed");
process.env.COOL_ENV_VAR; // => "stubbed"
import.meta.env.COOL_ENV_VAR; // => "stubbed"
vi.unstubAllEnvs();
process.env.COOL_ENV_VAR; // => "test"
import.meta.env.COOL_ENV_VAR; // => "test"
After yesterday's TIL, fellow Hashrocketeer Jack Rosa shared with me a few other cool ways to delete things in vim.
My favorite way that he showed me that I never knew existed was using dit
.
This deletes all content of the HTML tag you are inside of.
1 |<div>
2 | <h1>Header</h1>
3 |
4 | <p>
5 | This is some paragraph text that is <em>emphasized</em> for importance.
6 | </p>
7 |</div>
<div></div>
without being inside of a nested element, the result would be:1 |<div></div>
<em>emphasized</em>
, the result would be:1 |<div>
2 | <h1>Header</h1>
3 |
4 | <p>
5 | This is some paragraph text that is <em></em> for importance.
6 | </p>
7 |</div>
Conclusion: This is a nice and easy way to clear out html tags quickly.
If you want to delete the entire word that your cursor is sitting in, you can press diw
.
This deletes the word that you are inside of.
If you use a big W this will delete all the way in either direction until it hits whitespace, rather than just the end of the "word".
The HTTP 418 I'm a teapot client error response code indicates that the server refuses to brew coffee because it is, permanently, a teapot.
'Nuff said.
Check out the docs to learn more.
Thanks goes to Tony for making me aware of this.
If you want to conditionally add class names in Rails, here is a clean way to do it.
<%= link_to("Some Page", some_path,
class: class_names("bg-black text-black", {"text-white": text_visible?})
%>
This takes advantage of the class_names
method, which is just an alias for the token_list method.
h/t to Matt Polito.
I always find myself looking up his TIL and figured if I make it myself it will help me retain it. π
Today I learned that ISO 8601 includes a spec for durations as well as dates and times.
Normally when I think of ISO 8601 I think of dates (2024-05-30) or times (2024-05-30T19:54:14Z).
But it also includes a spec for durations! Super convenient to have a standardized way to represent this, and rails and javascript libraries are able to parse it.
Some examples:
PT8H
PT3H30M
P2M1D
P6Y5M4DT3H2M1S
Did you know you can look up ruby documentation on Classes and methods from the command line? The slightly elusive ri
command does just that. You can pass it an argument of the class/method you want to look up, or you can enter interactive mode without arguments.
$ ri uniq
$ ri Array#compact
$ ri Hash
You can also use it to browse all the pre-defined ruby global variables:
$ ri ruby:globals
Check out the docs or run ri --help
to see all it can do.
h/t Brian Dunn
Say you run your entire rspec suite and a couple of tests fail. You make a change that should fix them. How can you quickly rerun those failed tests to see if they're green? It could take minutes to run the whole suite again, and all you care about is 2 tests.
That's where the --next-failure
(-n
) flag comes in handy. According to the docs it is "Equivalent to --only-failures --fail-fast --order defined
)". So you can rerun only your failed specs, and exit immediately if one does fail. You could of course just use --only-failures
too, but sometimes it's nice to fail fast.
bundle exec rspec -n
h/t Brian Dunn
In Vim, if your cursor is over a word and you want to go to the next occurrence of that word in the file, just press *
.
If you want to go to previous occurrence of the word, just press #
.
Today I learned there are two ways to construct a
range in ruby. Using two dots ..
creates a range including the start and end values.
(2..5).include?(2) # => true
(2..5).include?(5) # => true
Using three dots ...
creates a range including the start value, but not the
end value.
(2...5).include?(2) # => true
(2...5).include?(5) # => false
So if we think of them in terms of
intervals, (a..b)
is
a closed interval ([a, b]
), and (a...b)
is a right half-open interval ([a, b)
).
Sometimes TypeScript can cache some things that you don't want it to keep cached. For example, an old lower case filename that doesn't exist anymore.
If this is the case, just restart your TypeScript server. If you're using Cursor or Visual Studio, just open up the command palette (Cmd + Shift + P
on macOS or Ctrl + Shift + P
on Windows/Linux) and type Restart TS Server
.
Say you had a committed file, foo.txt
and you wanted to rename that to Foo.txt
.
Well, on Mac, changing the file name will not show up when you run git status
.
So, what is the solution here?
git mv foo.txt Foo.txt
will rename the file, and let git keep track of it.
When Postgres is running comparisons, any null values will yield null at the end of the comparison. This is because the null is an unknown value that Postgres can't run the comparison against.
Take the following simple example of a users table and query:
create table users (name text, email text);
insert into users (name, email)
values ('Joe', 'joe@hashrocket.com'),
('Rick', null);
select * from users where email not like '%gmail.com';
-- name | email
-- ------+--------------------
-- Joe | joe@hashrocket.com
-- (1 row)
You'll notice that the Rick
user is not returned in the results.
If you want rows with the null value included in your results, you can coalesce the column to an empty string. This allows Postgres to run the comparison against two known values and return the rows with the null values.
select * from users where coalesce(email, '') not like '%gmail.com';
-- name | email
-- ------+--------------------
-- Joe | joe@hashrocket.com
-- Rick | ΓΈ
-- (2 rows)
ActiveSupport has a handy tool for handling exceptions globally in your Rails app. You can use it to catch specific exceptions and provide a centralized way to manage errors across your application, making your code cleaner and more maintainable.
Here is the example from the docs, showcasing how to catch specific exceptions and what method to run when they are caught.
Note: You can also pass it a block as the handler instead.
class ApplicationController < ActionController::Base
rescue_from User::NotAuthorized, with: :deny_access
rescue_from ActiveRecord::RecordInvalid, with: :show_record_errors
rescue_from "MyApp::BaseError" do |exception|
redirect_to root_url, alert: exception.message
end
private
def deny_access
head :forbidden
end
def show_record_errors(exception)
redirect_back_or_to root_url, alert: exception.record.errors.full_messages.to_sentence
end
end
If you are typing something in your shell and you need to delete the entire word you're on, instead of pressing backspace
repeatedly, you can press ESC
+ Backspace
and this will delete back to the start of the current word you are on.
Example; Say you wanted to delete this whole filepath, or a majority of it. Simply place your cursor at the end (or wherever you want to delete up to) and press ESC
+ Backspace
to delete all the way back to the word vim
vim /i/accidentally/typed/something/big/that/was/incorrect
and it might leave you with something like this
vim /that/was/incorrect
Today I learned about some focused reload
methods for ActiveRecord Associations.
Let's say I have an Author
class that can have one magnum opus.
class Author < ApplicationRecord
has_one :magnum_opus
end
Now suppose I've instantiated an Author
, and his magnum opus gets updated elsewhere. If I try to access that instance's magnum opus again (existing instance, no reloading), I'll get the old cached version:
author = Author.first
author.magnum_opus.title # => "The Dark Tower"
#elsewhere
mo = MagnumOpus.find_by(title: "The Dark Tower")
mo.update title: "The Shining"
author.magnum_opus.title # => "The Dark Tower"
Now to remedy this, we can reload the author:
author.reload.magnum_opus.title # => "The Shining"
But why reload the whole author when you can reload just the association? ActiveRecord has reload_*
methods for each has_one
and belongs_to
association that does just that - it reloads only the associated record.
author.reload_magnum_opus.title # => "The Shining"
Docs for has_one and belongs_to.
h/t Matt Polito
Use special markdown to emphasize content inside alert style content blocks on Github.
> [!NOTE]
> Highlights information that users should take into account, even when skimming.
> [!TIP]
> Optional information to help a user be more successful.
> [!IMPORTANT]
> Crucial information necessary for users to succeed.
> [!WARNING]
> Critical content demanding immediate user attention due to potential risks.
> [!CAUTION]
> Negative potential consequences of an action.
It can be kind of clunky to query ActiveRecord for records where the has_many
association is empty.
Say I have an Author
class that has many Books
. One way to query for Authors without books is the following:
class Author < ApplicationRecord
has_many :books
end
Author.left_joins(:books).where(books: {id: nil})
This totally works, but at least for me is difficult to reason what we're querying. However, Rails 6.1 added a .missing
method that really helps clarify what the query is doing:
Author.where.missing(:books)
Much clearer - this will grab all authors that do not have any books.
Docs for further reading. Happy querying!
You can set attributes to be used when creating new records with .create_with
:
Author.create_with(name: "Hashrocketeer")
Author.new.name # => "Hashrocketeer"
This can be particularly useful if you're doing a .find_or_create_by
and want to set some values only when creating:
Author
.create_with(post_count: 0)
.find_or_create_by(name: "Hashrocketeer")
This will find an author with name "Hashrocketeer". If we find an existing Author
, we won't change their post_count
. If we don't find an existing Author
, we'll create one with a post_count
of 0.
Read more in the docs
Today I learned about comm
, which is used to select the common lines in two files. It's pretty neat, but has a strange output format.
Say we have two text files:
# first.txt
one
two
three
# second.txt
one
three
four
We can run the below command to find the common lines. In the output, the first column is what's only in first.txt
, the second column is what's in second.txt
, and the third column is what's common.
$ comm first.txt second.txt
one
three
four
two
three
Hmm, that doesn't look right - one
and three
are common, not just one
. The caveat with comm
is that the files need to be sorted lexically. You can sort easily in bash with bird beak notation for process substitution.
$ comm <(sort first.txt) <(sort second.txt)
four
one
three
two
If we only want the common lines, we can apply the flags -12
to hide the first and second columns:
$ comm -12 <(sort first.txt) <(sort second.txt)
one
three