Today I Learned

A CCSalesPro project TwitterFollow on Twitter

26 posts by dillonhafer

Change rails server binding with ENV vars

You can change the rails server binding with an environment variable in addition to the CLI flags using the variable BINDING:

BINDING="::" rails server

Strict local variables

Rails partials let you do strict local variables with a magic comment:

<%# app/views/customers/_customer.html.erb %>
<%# locals: (customer:) -%>
<%= customer.name %>

If you don't pass a customer to the parital, it will raise an error:

<%= render "customer", not_customer: 42 %>

You must pass the customer:

<%= render "customer", customer: %>

Remove npm funding advertisements

When I run npm install or update I try to read the results to see if something went wrong. NPM floods this output with funding advertisements making it harder to read. This can be turned off with a config command:

npm config set fund false --location=global

Restrict a text column to numbers

create table only_numbers (
  my_column text not null check (my_column ~ '^[0-9]+$')
);

Rails can give the ordinal of any number

Integer's have an #ordinalize method that returns a string:

34.ordinalize + " street"
=> "34th street"

Disable DDL transactions with tern

You can disable DDL transactions during a migration with tern by adding the magic comment to the top of the migration file:

---- tern: disable-tx ----

create index concurrently on my_table (id);

Create a date duration from a string

Rails can parse ISO8601 date durations (PnYnMnDTnHnMnS) or ranges compatible for postgres daterange types:

ActiveSupport::Duration.parse("P1Y3M2D").parts
=> {:years=>1, :months=>3, :days=>2}

Escape strings for querySelector

You can sanitize strings passed to document.querySelector with CSS.escape

document.querySelectorAll(`.${CSS.escape("hover:bg-blue-400")}`);
=> NodeList(9)

Get the last quarter in Rails

Rails' Date like objects have a method to get to the next or previous quarter:

Date.current.last_quarter.beginning_of_month
=> Sun, 01 Oct 2023

Turbo frame will be in the request headers

If a request was made with a data-turbo-frame attribute, there will be a header turbo-frame with the same value:

<a data-turbo-frame="my-container" href="/promo">Click here</a>

There will be a header attached to the fetch request:

class Controller
  def promo
    puts request.headers["turbo-frame"]
    # => "my-container"
  end
end

Stimulus action options can preventDefault

Stimulus has action options like :prevent that will call prevent default on an event for you.

<button data-action="checkout#handleClick:prevent">click here</button>

This will cause the button's HTMLEvent to have event.preventDefault() called before it gets passed to the handleClick function. You can also add your own custom options.

The head tag can be referenced directly

Older methods of adding elements to the head of a document would search the document by tag names. Now a days you can reference head directly on document:

const script = document.createElement("script")
document.head.appendChild(script)

Older methods relied on document.getElementsByTagName("head")[0]

irb may be outdated

The irb gem can be more advanced than the version that comes with the current ruby version on your system. You can add irb to your gemfile to use a newer version.

bundle add irb

How to enable email previews in production

You can enable email previews in production, but be aware that these routes are public and have no authentication requirements, but you could do that with an upstream proxy.

# config/environments/production.rb
config.action_mailer.show_previews = true

Verify gpg commit signature

You can verify the gpg signature of a commit with git:

git verify-commit 360bcee8

Add months to a date with >>

In ruby you can add days to a date with the + method, and you can add months with >>:

require "date"
Date.today + 1
=> #<Date: 2023-07-11>

Date.today >>  1
=> #<Date: 2023-08-10>

Change form validation attribute name

Using rails' i18n gem and a en.yml file you can change the attribute of a form object:

en:
  attributes:
    fname:
      one: "First name"

Then you will see the new attribute name:

<div>Errors:</div>
<div>First name can't be blank</div>

Use a custom TLS cert with caddy

Caddy will accept an already issued tls certificate, instead of generating its own, by using the tls directive:

dillonhafer.com {
  tls /etc/ssl/certs/dillonhafer.com.pem /etc/ssl/private/dillonhafer.com.key.pem
}

Set default form builder globally

You can set a form builder globally, for all forms, by setting the value of default_form_builder in ApplicationController:

class ApplicationController < ActionController::Base
  default_form_builder MyFormBuilder
end


https://api.rubyonrails.org/classes/ActionController/FormBuilder.html

Pluralize words without displaying a count

The pluralize method is very familiar in rails to do things like:

<div>
  <%= pluralize(users.size, "users") %>
</div>

to see something like <div>4 users</div>

But strings have a pluralize method too:

puts "User".pluralize(4)
=> "Users"

Run all tests in a single go file

You can use sed to find all the test functions in a go file to pass to the regex flag:

// my_api_test.go
package my_api

func TestHappyPath(t *testing.T) {
}

func TestSadPath(t *testing.T) {
}

func TestHorriblePath(t *testing.T) {
}

func TestAwesomePath(t *testing.T) {
}

Test command:

go test -run $(sed -n 's/func.*\(Test.*\)(.*/\1/p' my_api_test.go | xargs | sed 's/ /|/g')

This runs:

go test -run TestHappyPath|TestSadPath|TestHorriblePath|TestAwesomePath

Add custom inflectors for irregular words

ActiveSupport::Inflector allows you to add custom inflections for words it doesn't know how to pluralize already:

# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.irregular "evidence", "evidence"
  #   inflect.plural /^(ox)$/i, "\\1en"
  #   inflect.plural /^(ox)$/i, "\\1en"
  #   inflect.singular /^(ox)en/i, "\\1"
  #   inflect.irregular "person", "people"
  #   inflect.uncountable %w( fish sheep )
end

This allows us to use evidence as a table name with a model called Evidence

puts "evidence".pluralize
"evidence"

Listen for trackpad pinch events in javascript

Desktop browsers do not implement the gesture events, so trackpads on desktop do not register pinch events like they do on mobile devices. However, pinch events come through as wheel events with the ctrl key depressed events 🤷‍♂️

let scale = 1;

document.body.addEventListener("wheel", function(e) {
  if (e.ctrlKey) {
    scale += e.deltaY * -0.01;
  }
});

How to spy on method calls in minitest

You can spy on a method in minitest with a Mock by calling #verify

mock = MiniTest::Mock.new
mock.expect :username

User.stub :find, mock do
  user = User.find(1)
  user.username
end

mock.verify

How to stub a method in minitest

In minitest you can stub a method my calling .stub and passing a method name:

class User
  def self.all
    42
  end
end

User.stub(:all, [1, 2, 3]) do
  assert_equal [1, 2, 3], User.all
end

Use a custom subdomain in an integration test

In an integration test ActionDispatch::IntegrationTest, you are not using Capybara, so you can't use Capybara.app_host=, but you can use the host! method to change the host url_for uses:

class MyTest < ActionDispatch::IntegrationTest
  def setup
    host! "admin.lvh.me"
  end

  test "#index" do
    visit my_url
  end
end