DotRuby Tapas.

Fresh from the oven - DotRuby Tapas are short tips and tricks we found in our daily work.
Best practices on tiny plates, easy to consume, easy to eat, easy to love!
πŸ₯˜ Hot and spicy 🌢️ knowledge about

#tailwindcss #rails #ruby #view components #visual studio code #regex #active storage #zsh #ohmyzsh #css #github #git

Use gems from private GitHub repos.

#github #ruby #rails

This brief guide walks you through the steps to install private gems hosted on GitHub.

GitHub personal access token

To authenticate bundler to GitHub, you will need a personal access token. Follow this guide to create one.

Setup Gemfile

Like any other gems, your private gem needs to be listed in your Gemfile. Add your private gem to the Gemfile:

gem "<gem>", git: "https://github.com/<owner>/<repo>.git", branch: "<branch>"

Use https link, it's important for the authentication part.

Setting up your credentials locally

This step may not always be necessary, depending on how you run the project locally and the permissions you have.
To set up your credentials, use bundle-config:

bundle config --local github.com "<personal access token>"

Install the gem dependencies using bundle install as usual.

Github Actions

You can specify env variables when running Github Actions, and that's what we'll use for authentication. Go to your repo's secrets page https://github.com/[user]/[repo]/settings/secrets/actions and create a repository secret with the personal access token. You can use it in your workflow file like so:

name: your_job

jobs:
  your_job:
    runs-on: ubuntu-latest
    env:
      BUNDLE_GITHUB__COM: "x-access-token:${{ secrets.PERSONAL_ACCESS_TOKEN }}"

Deploying

Just add the same BUNDLE_GITHUB__COM env variable to your server:

BUNDLE_GITHUB__COM=x-access-token:<personal access token>

And you are ready to deploy πŸš€

April 02, 2024 Victor Cobos

Use CSS Grid to stack items.

#css #tailwindcss

Skip position: absolute; for overlapping items. Use display: grid; and then position them in the same column + row.
🎩✨ Grid respects content size, a neat trick lost with absolute positioning.

Demo Screenshot

<div class="grid">
    <div class="item item--1"></div>
    <div class="item item--2"></div>
    <div class="item item--3"></div>
</div>

<style>
    .grid {
        display: grid;
    }

    .item {
        grid-row: 1;
        grid-column: 1;
    }

    .item--1 {
        transform: translate(-2rem, -2rem);
    }

    .item--2 {
        transform: translate(2rem, 2rem);
    }
</style>

Codepen demo

Alternatively, the shorthand method grid-area property to achieve the same result with more concise syntax. By setting grid-area: 1 / 1; on each item you wish to stack. Since the end lines for both rows and columns are not specified, they default to auto, which means the item will span one row, and one column from its starting position.

If you prefer to use TailwindCSS, that's no problem:

<div class="grid *:col-start-1 *:row-start-1">
    <div class="-translate-x-8 -translate-y-8"></div>
    <div class="translate-x-8 translate-y-8"></div>
    <div></div>
</div>

TailwindCSS demo

March 27, 2024 Victor Cobos

Profiling zsh setup with zprof.

#zsh #ohmyzsh

Leveraging frameworks like oh-my-zsh can enrich your shell experience, but overloading it with plugins might slow things down. Keeping your .zshrc file lean can significantly enhance startup times and overall performance. Profiling your shell is a good start to figuring out what is slowing it down.

Zprof is a utility that comes packaged with zsh, which you can use to profile your zsh script.
Add the following to the top of your .zshrc file to load zprof:

if [[ -n "$ZSH_DEBUGRC" ]]; then
  zmodload zsh/zprof
fi

And this at the bottom:

if [[ -n "$ZSH_DEBUGRC" ]]; then
  zprof
fi

To profile your .zshrc script and print a summary of all the commands run during your shell startup and the time it takes to execute them run this:

time ZSH_DEBUGRC=1 zsh -i -c exit

Recommendation would be to put this in an alias to make everything more comfortable.
Running the command will print something like this:

This approach will reveal which commands are the most time-consuming to load, setting you on the path to efficient customization. Happy profiling!

March 22, 2024 Victor Cobos

Purge unattached ActiveStorage::Blobs.

#active storage

When's the last time you cleaned up those ActiveStorage::Blobs hanging around without attachments?

namespace :active_storage do
  desc "Purges unattached ActiveStorage::Blobs"
  task purge_unattached: :environment do
    ActiveStorage::Blob.unattached.where(created_at: ..2.days.ago).find_each(&:purge_later)
  end
end

If you're handling direct uploads consider running this rake task periodically to keep the cloud bucket clean and avoid paying for storage that's not being used.

March 09, 2024 Victor Cobos

Unlocking the Superpower of Regular Expressions in Find and Replace for Visual Studio Code.

#visual studio code #regex

When looking to modify large sections of text, the Find and Replace functionality in Visual Studio Code can be incredibly useful. This tool becomes even more powerful when combined with regular expressions, enhancing its precision and flexibility.

To use regex in VS Code, open the Find widget (Ctrl + F or Cmd + F on macOS) or the Replace widget (Ctrl + H or Cmd + Alt + F on macOS). You'll notice a .* button on the left side of the box. Clicking this button activates the regex mode, allowing you to enter your regex search patterns.

A key aspect of this technique involves using capturing groups, marked by parentheses (), which can be cleverly referenced in the replacement pattern using $number, with $0 denoting the full match. To incorporate a $ symbol in your patterns, you'll use $$.

Let's apply this concept with a simple example: transforming date formats. Suppose you have a list of dates in the format mm/dd/yyyy within your document and you wish to convert them to the ISO standard format yyyy-mm-dd. This transformation can be easily achieved with regular expressions in the Find and Replace functionality. The find pattern would be (\d{2})/(\d{2})/(\d{4}) and the replace pattern $3-$1-$2, showing just how straightforward it can be.

Screenshot showing Visual Studio Code Regular Expressions search

Dive into the flexibility it offers, and turn tedious tasks into quick fixes. Happy replacing with regex!

February 29, 2024 Victor Cobos

Rendering view component template variants outside of the current request.

#view components #rails

Rails variants are a technique to allow rendering of different template or partial variants, for example, to render different web and ios/android views, even though the underlying controller logic is the same. If you'd have a partial _new.html.erb, you'd could also provide a partial _new.html+ios.erb which would automatically being called if the request object is set to this preferred variant.

As heavy users of GitHub's view_component gem, we are happy that the gem supports variants natively as well. However, sometimes we run into a situation where we want to access a variant of the component without relying on the current request variant. It turns out that calling the component with the usual render MyComponent.new, variant: 'custom_variant' does not work. It's tight to the current view context of the given controller.

Luckily there is the Rails ActionController::Rendering class, which is exactly made for this: To render arbitrary templates without being inside a controller action.

So, for example, if you are in a place in your Rails view and you need to explicitly address a variant template that is outside the current view_context variant, you can do so with:

<%= ApplicationController.render(MyComponent.new, variant: 'custom_variant') %>
February 22, 2024 Daniel Schoppmann

Accessing TailwindCSS Configurations from JavaScript.

#tailwindcss

There are instances where the design settings defined in TailwindCSS, such as themes, spacing, or breakpoints, are essential for JavaScript logic to ensure a cohesive user experience. Whether it's dynamically changing themes, adjusting layouts based on viewport sizes, or creating consistent animations, accessing these design settings directly from JavaScript is indispensable. This would also help you to keep the code DRY.

To make this easy, Tailwind provides a resolveConfig helper you can use to generate a fully merged version of your configuration object:

import resolveConfig from 'tailwindcss/resolveConfig';
import tailwindConfig from '../tailwind.config.js';

const fullConfig = resolveConfig(tailwindConfig);

fullConfig.theme.width[4]
// => '1rem'

fullConfig.theme.screens.md
// => '768px'

fullConfig.theme.boxShadow['2xl']
// => '0 25px 50px -12px rgba(0, 0, 0, 0.25)'

Leveraging TailwindCSS settings in JavaScript bridges the gap between style and logic, ensuring your code is as efficient as it is elegant - a true hallmark of modern web development.

February 21, 2024 Victor Cobos

Split your routes.rb file into logical files.

#rails

If you have a typical monolithic Rails application, you have probably already divided your application into logical namespaces or modules. Did you know that you can do the same with your routes?
Typically, all routes are stored in the routes.rb file. But this can get pretty messy when you have hundreds of lines to scan. Fortunately, Rails allows you to split routing files using the internal draw method.
So instead of having one big routing file, we like to split our routes into their selective units. For example, if we have an admin area, an api, and the actual application itself, the routes.rb file can look as simple as this:

Rails.application.routes.draw do
  draw :admin
  draw :api
  draw :app
end

Now each namespace is easy to understand and can be defined on its own, for example in config/routes/admin.rb

namespace :admin do
  # Place your admin routes here
end

Of course, namespaces themselves already come with a decent structure in the routes file, but as said, in very large applications, splitting your routes into smaller files may help for better clarity.

February 09, 2024 Daniel Schoppmann

Add zeitwerk:check rake task to you CI system.

#rails

Zeitwerk is the internal code loader for Rails. Rails delegates all autoloading of ruby files to Zeitwerk, which is itself super powerful and highly customizable. By default, Zeitwerk expects your ruby files to have specific filenames, so a class like class VATChecker and a corresponding vat_checker.rb file won't work. While there are easy ways around this, we have sometimes run into this error and there have been times where the production application did not start because of a code loading error that slipped through in dev mode.

Fortunately, there is an easy-to-use zeitwerk:check rake task that you can use to ensure that your Rails application will boot properly in production. This is especially useful if you have renamed some classes with a structure that Zeitwerk does not expect and your test system does not (yet) catch the new files. Or you have an old codebase and want to upgrade to a newer version of Rails. Best to add it to your CI system of choice so you can catch errors like this up front.

bundle exec rails zeitwerk:check
February 08, 2024 Daniel Schoppmann

Count occurrences with the .tally method.

#ruby

You might know that Rails turns an ActiveRecord Relation filled with a .group and a .count call in a very handy Hash result object, where each grouped attribute is the key and the value is the direct count of the attributes's ocurances.

Post.group(:state).count 
=> {"draft" => 2, "published" => 5}

Ruby itself provides a similar functionality with the .tally method which is available in the Enumarable module. So whenever you have an array e.g. it’s now super easy to get the count of each element occurances within the array. The method has been in the standard lib since Ruby 2.7.

array = %w(draft published published draft published)
array.tally
=> {"draft" => 2, "published" => 3}
February 08, 2024 Daniel Schoppmann
Subscribe to get future tapas via the RSS feed .