Here's the second weekly recap!
In last weeks recap, I shared where we were at in code and it looked like this:
# test_helper.rb
Oaken::Data.load_from "test/seeds"
# test/seeds/users.rb
User = Struct.new(:name, keyword_init: true)| create_table :stowaway_records do |t| | |
| t.string :record_type, null: false | |
| t.jsonb :record_attributes, null: false, default: {} | |
| t.timestamps | |
| t.index :record_type | |
| end | |
| class Stowaway::Record < ActiveRecord::Base | |
| def self.preserve(record) | |
| create! record_type: record.class, record_attributes: record.attributes |
| donuts = accounts.create :kaspers_donuts, name: "Kasper's Donuts" | |
| kasper = users.create :kasper, name: "Kasper", accounts: [donuts] | |
| coworker = users.create :coworker, name: "Coworker", accounts: [donuts] | |
| menu = menus.create account: donuts | |
| plain_donut = menu_items.create menu: menu, name: "Plain", price_cents: 10_00 | |
| sprinkled_donut = menu_items.create menu: menu, name: "Sprinkled", price_cents: 10_10 | |
| supporter = users.create name: "Super Supporter" |
Here's the second weekly recap!
In last weeks recap, I shared where we were at in code and it looked like this:
# test_helper.rb
Oaken::Data.load_from "test/seeds"
# test/seeds/users.rb
User = Struct.new(:name, keyword_init: true)| class FormBuilder | |
| def text_field(method, **options) | |
| tag.input type: :text, **options_for(__method__, method, **options) | |
| end | |
| def options_for(type, method, index: @index, namespace: @options[:namespace], multiple: false, **options) | |
| Options.new(self, type, method, index:, namespace:, multiple:, **options) | |
| end | |
| class Options |
| # Provide a BulletTrain::Theme::FormBuilder, with extensions to | |
| # go between Rails standard form helpers and BulletTrain's themed versions seamlessly. | |
| # With standard Rails: | |
| # form_with model: Post.new do |form| | |
| # form.themed.text_field # Use BulletTrain theming on just one field | |
| # | |
| # form.themed.fields do # Need a nested section of fields but themed? | |
| # end | |
| # end |
| class Object::Proxy < SimpleDelegator | |
| def initialize(object, **values) | |
| super(object) | |
| @values = values | |
| end | |
| def method_missing(name, ...) | |
| @values.fetch(name) { super } | |
| end | |
| end |
| 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 |
| 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 |
| # 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 |