Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
JoshCheek / ar_lazy_preload_example.rb
Created Jun 21, 2022
ar_lazy_preload example (for graphql without N+1 issues)
View ar_lazy_preload_example.rb
# Config
require 'rails'
require 'ar_lazy_preload' # https://github.com/DmitryTsepelev/ar_lazy_preload
require 'active_record'
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
# not sure where this is supposed to happen, but it's necessary b/c ar_lazy_preload
# adds its functionality in a callback after active record finishes loading.
ArLazyPreload::Railtie.config.to_prepare_blocks.each(&:call)
@JoshCheek
JoshCheek / active_record_comparing_different_ways_to_load_associated_data.rb
Created Jun 8, 2022
ActiveRecord: Comparing different ways to load associated data (`includes` vs `preload` vs `eager_load`)
View active_record_comparing_different_ways_to_load_associated_data.rb
# Config
require 'active_record'
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
# Migrations
ActiveRecord::Schema.define do
self.verbose = false
create_table(:users) { |t| t.string :name }
create_table :posts do |t|
t.string :name
@JoshCheek
JoshCheek / cancancan_raise_on_undeclared_abilities.rb
Created Jun 8, 2022
Modifying CanCanCan's default behaviour to raise when asked about undeclared abilities
View cancancan_raise_on_undeclared_abilities.rb
gem 'cancancan', '= 2.1.2' # the version from our gemfile
require 'cancan'
module CanCan::StrictAbility
include CanCan::Ability
# Overrides this method: https://github.com/CanCanCommunity/cancancan/blob/2.1.2/lib/cancan/ability.rb#L67-L74
# NOTE: on newer cancans, the implementation of that method changed to allow attribute level rules
def can?(action, subject, *extra_args)
had_relevant_rule = false
@JoshCheek
JoshCheek / not_cancancan.rb
Last active Jun 4, 2022
What I feel like cancancan abilities should have been
View not_cancancan.rb
# Library implementation of what it feels like cancan should have been
module NotCanCan
class Permission
attr_reader :verb, :direct_object, :default, :dynamic_override
def initialize(verb, direct_object, default, &dynamic_override)
@verb, @direct_object = verb, direct_object
@default, @dynamic_override = !!default, dynamic_override
end
View cancancan_ability_composition_strategy.rb
require 'cancan'
# Some models
Post = Struct.new(:author, :published, :body) { alias published? published }
User = Struct.new(:name, :admin) { alias admin? admin }
# Abilities
class CommonAbility
include CanCan::Ability
def initialize(user)
@JoshCheek
JoshCheek / active_record_upsert_example.rb
Last active May 26, 2022
ActiveRecord upsert example
View active_record_upsert_example.rb
# configure activerecord (in-memory sqlite db to keep it simple)
require 'active_record'
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
# helper method for asserting expectations
def check!(expected, operator = :==, actual)
equal = expected.public_send(operator, actual) and return
raise RuntimeError, <<~MESSAGE, caller
test: #{expected.inspect} #{operator} #{actual.inspect}
expected: true
@JoshCheek
JoshCheek / how_do_I_fix_the_n+1_query.rb
Last active May 26, 2022
How do I define the association in a way that gets rid of this N+1 query?
View how_do_I_fix_the_n+1_query.rb
# Asking the twitterverse how to deal with this: https://twitter.com/josh_cheek/status/1529326801654358023
# Configure ActiveRecord
require 'active_record'
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
# Migrations
ActiveRecord::Schema.define do
self.verbose = false
create_table :users do |t|
View rails_bug.rb
# Was super struggling to get my array to validate (nil is bad, empty array is fine, nonempty array should contain strings)
# Finally went and read the code, and it looked totally buggy (b/c `nil` is `blank?`:
# https://github.com/rails/rails/blob/25b126707152de3a1ec9762ee564f3c7623373b3/activemodel/lib/active_model/validator.rb#L151
# Made this test to demonstrate.
require 'active_model'
def test(*values, **validation)
[false, true].product([false, true]).map.with_index 1 do |(allow_nil, allow_blank), index|
klass = Struct.new(:values, keyword_init: true) { include ActiveModel::Validations }
@JoshCheek
JoshCheek / ruby_case_statements_rase_when_unmatched.rb
Created May 5, 2022
Example of how to deal with Ruby case statements
View ruby_case_statements_rase_when_unmatched.rb
# https://twitter.com/josh_cheek/status/1522312126995611651
def UnmatchedCase(...)
UnmatchedCase.new(...)
end
class UnmatchedCase < RuntimeError
PENDING = Struct.new(:inspect).new('(PENDING)')
attr_reader :description, :value
def initialize(description, value = PENDING)
@JoshCheek
JoshCheek / example.rb
Created Apr 12, 2022
Example of using UUIDs for primary keys in ActiveRecord
View example.rb
require 'active_record'
ActiveRecord::Base.establish_connection adapter: 'postgresql', database: 'josh_test'
ActiveRecord::Schema.define do
self.verbose = false
enable_extension 'pgcrypto'
create_table :conversations, id: :uuid do |t|
t.string :topic
end
create_table :messages, id: :uuid do |t|
t.uuid :conversation_id, null: false, index: true