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.
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 π
Use CSS Grid to stack items.
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.
<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>
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>
Profiling zsh setup with zprof.
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!
Purge unattached ActiveStorage::Blobs.
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.
Unlocking the Superpower of Regular Expressions in Find and Replace for Visual Studio Code.
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.
Dive into the flexibility it offers, and turn tedious tasks into quick fixes. Happy replacing with regex!
Rendering view component template variants outside of the current request.
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') %>
Accessing TailwindCSS Configurations from JavaScript.
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.
Split your routes.rb file into logical files.
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.
Add zeitwerk:check rake task to you CI system.
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
Count occurrences with the .tally method.
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}