Skip to content

Instantly share code, notes, and snippets.

View searls's full-sized avatar
💚

Justin Searls searls

💚
View GitHub Profile
@searls
searls / validates_deeply.rb
Last active April 23, 2024 16:07
Is this overkill? Is there some other nice way to do this?
class ValidatesDeeply
Failure = Struct.new(:model, :message)
Result = Struct.new(:valid?, :failures)
def validate(model, visited = Set.new)
return Result.new(true) if visited.include?(model)
visited.add(model)
combine_results(Result.new(model.valid?, extract_failures(model)), *validate_associations(model, visited))
end
:root,
.light {
--accent: 183 64 233;
--accent-bright: 183 64 233;
--accent-light: 217 155 244;
--bg-primary: 249 249 249;
--bg-secondary: 230 230 230;
--border-primary: 17 24 39;
const css4ColorsToLegacyRgbaPlugin = {
postcssPlugin: 'these-colors-dont-run',
Once (root) {
root.walkDecls((decl) => {
const rgbRegex = /rgb\((\d{1,3})\s+(\d{1,3})\s+(\d{1,3})\s*(?:\/\s*(\d+\.?\d*))?\)/g
decl.value = decl.value.replace(rgbRegex, (match, r, g, b, a) => {
if (!a || a === '1' || a === '1.0') {
return `rgb(${r}, ${g}, ${b})`
} else {
return `rgba(${r}, ${g}, ${b}, ${a})`
@searls
searls / ensures_logger_broadcasts_to_stdout.rb
Last active March 4, 2024 19:18
This logger wrapper I wrote.
# Leverages the BroadcastLogger introduced in Rails 7.1 to wrap the current
# logger in a new logger that broadcasts to both the current logger and $stdout
#
# (Announcement: https://rubyonrails.org/2023/9/29/this-week-in-rails)
#
# If the current logger already broadcasts to $stdout, it will not be wrapped,
# making it safe to call this method multiple times without knowing the current
# logging "sitch".
#
# Usage probably looks something like this:

Running with patch

$ QUEUE_ADAPTER=async ./fix-preview-image-race-condition.rb 

Yields

Creating a post and uploading a video
@searls
searls / readme.md
Created January 31, 2024 16:15
Uncovered a race condition when multiple preprocessed variants are specified for a previewable attachment (e.g. PDF, videos) and multiple TransformJob jobs are enqueued after create

TIL this script helped me figure out that

  1. Given a previewable attachment (video, pdf) has 2 preprocessed variants
  2. After being attached, these are enqueued [ActiveStorage::AnalyzeJob, ActiveStorage::TransformJob, ActiveStorage::TransformJob]
  3. All 3 jobs will (I assume?) separately download the video from storage to a tmp file
  4. Running asynchronously, a race condition results: both transform jobs will see no blob.preview_image exists yet and will BOTH create one
  5. Since a blob only has one preview_image attached, one preview image (and any variants associated with it) will be orphaned
  6. As a result when the attachment is purged, those orphaned blobs and variant record will fail to be purged

Not awesome things that happen in this case:

@searls
searls / feeds_controller.rb
Created January 7, 2024 15:41
Abbreviated example code that was exhibiting an N+1 only for non-image (video/pdf) preview representations
class FeedsController < ApplicationController
def index
@posts = Post.with_visuals.order(published_at: :desc)
end
end
@searls
searls / github
Created November 16, 2023 02:11
I got sick of going through multiple steps to visit the current directory's github URL when I'm looking at a terminal, but I don't necessarily want to install `gh` or `hub` just for this feature.
#!/usr/bin/env ruby
begin
repo = `git remote -v`.split("\n").find { |line|
line.include?("github.com")
}.split("\t")[1].match(/git@github.com:(.*).git/)[1]
system "open https://github.com/#{repo}"
rescue
warn "No github remote found"
@searls
searls / run
Created October 17, 2023 15:03
LOL, I wrote a Ruby script for generating spreadsheets conversationally with GPT-4.
~/code/searls/spreadsheetify $ ./script/run
Let's define columns.
Column name:
> Name
Column description: (optional)
>
More columns? [Yn]
>
@searls
searls / feedback_loops.rb
Last active July 24, 2023 16:26
A script for illustrating feedback loops completed given various conditions for a post on https://justin.searls.co
WORKDAY_HOURS = 8
LOOP_SPEED = 15
INCORRECT_EVERY = 25
LOW_FIDELITY_EVERY = 10
INCORRECT_LOOP_PENALTY = 3
LOW_FIDELITY_TIME_PENALTY = 2
time_remaining = WORKDAY_HOURS * 60 * 60