Today I Learned

hashrocket A Hashrocket project

22 posts by jackrosa

Pattern Matching Args with Exact Values

In elixir there is a handy trick for pattern matching for exact values. Let's say we have a function head_match that takes two arguments, a string and a list, that checks if the string argument is the same as the head of the list. We could use pattern matching like this:

def head_match(head, [head, _tail]) do
  IO.puts("Thats the head of the List!")
end
#this will match if we called it like head_match("first_word", ["first_word", "second_word"])

See how we named the first argument head and used that same name as the list head? This means that the function will only match if those two values are the exact same rather than just matching the structure of the arguments.

Shorthand Elixir Anonymous Functions

Elixir has a really cool syntax for writing anonymous functions (unnamed functions). It goes like this:

# The '&' operator is used to define the function and its arguments
putter = &(IO.puts &1)
putter.("Today I learned")
#...> Today I learned
#...> :ok

&1 refers to the functions first argument; in this example, we used "Today I learned". You can use more arguments with &2, &3, etc... For example:

combiner = &(&1 <> &2)
combiner.("Foo", "Bar")
#...> "FooBar"

Also notice that we are not calling either of these functions like function(arg1, arg2), instead we are calling them like function.(arg1, arg2). We have to use . because we are not actually naming these functions, we are only assigning them a reference, hence "anonymous" functions.

The difference between %w and %W in Ruby

%w can construct space delimited word arrays like this

%w(my cool word array)
#=> ["my", "cool", "word", "array"]

%W works similarly, however it offers ways to interpolate with variables and escape special characters in the assignment, while %w does not.

street_name = 'Sesame Street'
%W(I live on #{street_name})
#=> ["I", "live", "on", "Sesame Street"]

Direct many-to-many ActiveRecord associations

By using has_and_belongs_to_many you can directly relate models with a many-to-many-association. For example, if you have a model Film and a model Producer, a film can have multiple :producers, and a Producer can have multiple :films; in this case, each of models could have a has_and_belongs_to_many association with the other.

#film.rb
class Film < ApplicationRecord
  has_and_belongs_to_many :producers
end

#producer.rb
class Producer < ApplicationRecord
  has_and_belongs_to_many :films
end
#Now associative records can be stored and retrieved
film = Film.where(title: "The Irishman")
producer = Producer.where(name: "Martin Scorcese")
film.producers << producer
film.save

producer.films
#=> This should return a collection including The Irishman
films.producers
#=> This should return a collection including Martin Scorcese

Creating Custom Typescript Types

In TypeScript you can build your own custom object types. Custom types work just like any other type. You can use it like this:

type Vehicle = {
    make: string, 
    model: string, 
    capacity: number, 
}

//now we can use the vehicle type in a definition
const corolla: Vehicle = {
    make: "Toyota",
    model: "Corolla", 
    capacity: 5,
}

If you define a vehicle without any of the required types, TypeScript will provide an error stating which property is missing from the object. For example:

const corolla: Vehicle = {
    make: "Subaru",
    model: "Outback", 
}

This definition will provide an error Property 'capacity' is missing in type '{ make: string; model: string; }' but required in type 'Vehicle'., because the capacity property is missing.

Encrypting database columns with Rails 7

In Rails 7, Active Record includes the option to encrypt database columns. To start run bin/rails db:encryption:init, then copy the resulting keys to your app's credentials.yml. Now in your model, you can tell Active Record to encrypt a column by using the encrypts which takes a db column name as an argument. For example:

class User < ApplicationRecord
  encrypts :super_secret_data
end

Active record will automatically decrypt the data upon retrieval. See more here.

Execute CDP from a Capybara test

Selenium Chrome:

With capybara you can access the page's driver by using page.driver. Next you can access the browser methods on the driver withpage.driver.browser, then the .execute_cdpmethod can be used to execute chrome devtools commands on your webdriver browser.

In a capybara test, it could like:

test_browser = page.driver.browser

coordinates = { latitude: 35.689487,
                longitude: 139.691706,
                accuracy: 100 }

test_browser.execute_cdp('Emulation.setGeolocationOverride', **coordinates)

This can be used to mock some client-side information such as user device metrics, geo-location, or even emulate slow CPUs 😳

Truncate by Word Count in Rails

Rails has a convenient method for truncating strings based on word count.

my_string = "Hello World you are now reading a til post"
my_string.truncate_words(2) 
#=> "Hello World..."

The method automatically adds ... to the end of the string to indicate that the string has been shortened. You can customize this omission by passing an omission argument.

my_string.truncate_words(2, omission: "... (read more)")
#=> "Hello World... (read more)"

Attaching Fixture Files in Rails Model Tests

If you want to attach fixture files in a model test. Assuming your ActiveStorage association is already set up, if it's not set up, check this out, then follow these steps:

  1. Make sure your desired fixture file has been placed in your test/fixtures/files folder
  2. Attach the fixture to the model instance by providing the .attach method with a hash including an IO object and the name of the file you wish to attach.

It should look something like this:

@object.image.attach(io: File.open('test/fixtures/files/filename'), filename: 'filename')

Limiting object counts in rails associations

Let's say you have a model owner and a model pet. Every owner has_many pets, but you want to limit the number of pets an owner can have. You can use the following validation in your model to make sure these owners don't get greedy with their number of pets.

has_many :pets
validates :pets, length: { maximum: 5 } 

The length helper is telling rails to only allow an owner to have a maximum of 5 pets. This is a little awkward because the length helper usually pertains to enforcing a minimum or maximum length on a string attribute, but it still works on the ActiveRecord Association Collection of :pets in a similar way where it is basically validating the maximum size of the collection.

Rails TimeHelpers

Rails ActiveSupport testing library includes some really helpful methods for manipulating time.

Here's a cool one:

travel_to Time.new(2022, 9, 14) do  
    #everything inside this block is now happening as if it is 9-14-2022

end
# afterwards we return to the present

This way you can test all sorts of time-based features by jumping back and forth through time.

Trippy 🔮

Duplicating tabs in iTerm

If you want to open a new tab in iTerm in your same working directory, you can use the following steps:

  1. Navigate to preferences or use (⌘,).
  2. Click on the Keys settings.
  3. Hit + in the bottom left corner to add a new shortcut.
  4. Record a shortcut of your choosing
  5. Using the dropdown menu for Action: select 'Duplicate Tab"

Now your new shortcut will open a new iTerm tab in whatever directory you have currently open.