Skip to content

Instantly share code, notes, and snippets.

View kaspth's full-sized avatar

Kasper Timm Hansen kaspth

View GitHub Profile
class Developer
has_object :search_scorer, after_save_commit: :rebuild_later # Forward callback onto context object.
end
# From my https://github.com/kaspth/active_record-associated_object gem.
# app/models/developer/search_scorer.rb
class Developer::SearchScorer < ActiveRecord::AssociatedObject
performs :rebuild # Adds `rebuild_later` to automatically generate a job to run the scoring calculation in.
def rebuild
record.update! search_score: new_score
@kaspth
kaspth / a_expositions_from_secondary_service.rb
Last active April 6, 2023 16:56
Let secondary services deliver expositions to a primary service intake which it may process, everything happens on a private network.
class Invoice
delivers_exposition # only: :create ?
# ^ shorthand for this:
after_create_commit -> { Exposition.deliver_later "invoice.create", self }
after_update_commit -> { Exposition.deliver_later "invoice.update", self }
after_destroy_commit -> { Exposition.deliver_later "invoice.destroy", self }
end
class Exposition < Data.define(:service, :event, :gid)
def initialize(service: "invoices", **) = super
@kaspth
kaspth / action_view.rb
Created December 29, 2022 15:03
Very condensed write up of Action View's rendering
# app/views/cards/_card.html.erb
# <%= greeting %>
#
# ^ gets compiled onto ActionView::Base as a Ruby method, when called like this:
#
# render "cards/card", greeting: "Hello"
#
# Here's roughly what the compiled source looks like:
class ActionView::Base
def render_card(local_assigns, output_buffer) # Not the actual method name, and the arguments change if using strict locals
require "tsort"
module Rails
module Initializable
extend ActiveSupport::Concern
def run_initializers(group = :default, *arguments)
@ran ||= true.tap do
Initializer.tsort(initializers).each { instance_exec(*arguments, &_1.block) if _1.in?(group) }
end
@kaspth
kaspth / method_chain.rb
Created December 18, 2022 17:48
A half written-up implementation of progressively enhancing an options hash through method chaining on a context object.
class Method::Chain
def initialize(descriptor, **options)
@descriptor, @options = descriptor, options
end
def self.define(context, *methods, &block)
instance = new Definition.new(&block)
instance.apply context, *methods
instance
end
# app/controllers/feeds_controller.rb
class FeedsController < ApplicationController
before_action :set_feed
def show
# Not sure if I like this but there could be something similar to interactors?
action do
_1.success.html { redirect_to @feed, notice: "Success" }
_1.success.json
_1.unprocessible { render :new }
# Add a module builder that'll mask each class method?
def self.required_condition_via(scopes)
prepend RequiredCondition.new(scopes)
end
module RequiredCondition
def initialize(scopes)
@scopes = scopes
end
@kaspth
kaspth / routes.rb
Last active April 6, 2023 16:57
`draw` method to explore routes in the console
# All these requires are just for running via `irb`, if using `bin/rails console` you probably just need the method.
require "active_support/all" # Got an inflector NoMethodError, so I'm just being lazy here.
require "action_dispatch"
require "action_dispatch/routing/route_set"
require "action_dispatch/routing/inspector"
require "action_controller" # For the ActionController::Parameters autoload, which any route helper uses.
# Console helper play around with the routing DSL and tweak an individual route you're building.
@kaspth
kaspth / scope_with_class_methods.rb
Created July 1, 2022 11:22
`scope` extension to allow marking a class method as a scope.
# In Active Record, class method scopes have to remember to return `all` otherwise they're break the call chain.
#
# def self.some_scope = nil # Assume more complex conditions that would result in a branch that accidentally didn't return `all`.
#
# User.some_scope.first # => raises NoMethodError `first' for NilClass
#
# Note: Active Record ensures a `scope :some_scope, -> { nil }` returns `all` via `|| all` here:
# https://github.com/rails/rails/blob/c704da66de59262f4e88824589ae4eddefb6ed4a/activerecord/lib/active_record/scoping/named.rb#L181
#
# Now, this extension allows you to mark a class method as a scope, so you don't have to remember and the code is more clearly demarcated too.
@kaspth
kaspth / output.rb
Last active June 6, 2019 21:30
Playground: test `segment` as a more broad `partition`.
# Ruby's Enumerable has `partition` to split it into true and false groups.
evens, odds = 1.upto(5).partition(&:even?)
evens # => [ 2, 4 ]
odds # => [ 1, 3, 5 ]
# But what if you have more than 2 segments? Well, here I'm playing with one way to do it.
# Respectively outputs:
# [[:first, :first], [:second, :second], [:third, :third]]
# [[:first, :first], [:second, :third, :second, :third]]