Today I Learned

hashrocket A Hashrocket project

36 posts by marylee twitter @marybethlee11

Ruby memoization with nil values

As Ruby developers, we’re often looking for ways to reduce time consuming lookups in our code. A lot of times, that leads us to memoizing those lookups with the common ||= operator.

However, if our lookups return a nil or falsey value, our memo will actually keep executing the lookup:

def ticket
  @ticket ||= Ticket.find_by(owner:)

This code essentially boils down to:

def ticket
  @ticket = @ticket || Ticket.find_by(owner:)

If our find_by in the example above returns nil, the code will continue to run the find_by every time we call the ticket method.

To avoid this, we can shift our pattern a bit, and look to see if we have already set our instance variable or not:

def ticket
  return @ticket if defined?(@ticket)
  @ticket = Ticket.find_by(owner:)

Ruby Squeeze

Ruby has a method to remove repeating characters in a string called squeeze

# => "fobar"

"foo foo bar".squeeze
# => "fo fo bar"

It also accepts args to narrow down the specific characters for which you would want to remove repeats:

"foobar hello world".squeeze("o")
# => "fobar hello world"

"foobar  hello  world".squeeze(" ")
# => "foobar hello world"

Rails scopes might just return all resources

ActiveRecord’s scopes are meant to be composable and intended to only ever return an ActiveRecord relation.

If you make a mistake with your scope and have it return something like a nil or false, Rails will return all records for that class in order to maintain composability.

If you are intentionally writing something that might return an empty value, use a class method rather than adding a scope in order to prevent bugs

undef_method vs remove_method

Ruby’s undef_method and remove_method are both methods for removing a method from a class, but there are subtle differences between the two.

Say we have two classes that both define the method name, with one class inheriting from the other:

class Human
  def name
    "homo sapien"

class Child < Human
  def name
    "small homo sapien"

remove_method fully deletes a method from a particular class, but will still look for the method on parent classes or modules when called on the particular class:

child =
# => "small homo sapien"

class Child
  remove_method :name
# => "homo sapien"

undef_method in contrast will prevent Ruby from looking up the method on parent classes

child =
# => "small homo sapien"

class Child
  undef_method :name
# => raises NoMethodError
# undefined method `name' for #

Append items to an array

Today I came across yet another way to add items to an array in ruby

I already knew about push and <<, but did you know that there’s also an append?

# => [1,2,3,4]

[1,2,3] << 4
# => [1,2,3,4]

# => [1,2,3,4]

append is ultimately just an alias for push, but always good to know!

Postgres regex matching with squiggles

Postgres supports POSIX regex pattern matching using the squiggle (~) operator

-- Check for a match
select 'wibble' ~ 'ubb';
-- returns false
select 'wibble' ~ 'ibb';
-- returns true

-- Case insensitive match checking
select 'wibble' ~ 'IBB';
-- returns false
select 'wibble' ~* 'IBB';
-- returns true

-- Check for no match
select 'wibble' !~ 'ibb';
-- returns false
select 'wibble' !~ 'ubb';
-- returns true

Full postgres pattern matching documentation can be found here

Find the position of a substring in postgres

Postgres has a strpos function for finding the position of a substring in a given string:

select strpos('wibble', 'ibb');

The function returns an integer representing the location of the substring in the provided string, or a 0 if the substring cannot be found in the provided string (the locations are 1-based indexes, so you don’t have to worry about collisions!).

Set JSON.parse returned object and array classes

By default, the Ruby JSON.parse method returns a ruby Hash for any json object, and a ruby Array for any json array.

However, you can customize the returned object classes using the object_class and array_class options:

source = JSON.dump({ wibble: "wubble", data: [1,2,3] })

result = JSON.parse(
  object_class: OpenStruct,
  array_class: Set
# => #> # => #
result.wibble # => "wubble"

There's a "whereami" alias in Pry

Since version 0.10.0, the pry gem has shipped with a built in alias for whereami: the extremely convenient @

Other useful aliases can be found using the help command:

[1] pry(main)> help

  !!!                Alias for `exit-program`
  !!@                Alias for `exit-all`
  $                  Alias for `show-source`
  ?                  Alias for `show-doc`
  @                  Alias for `whereami`
  clipit             Alias for `gist --clip`
  file-mode          Alias for `shell-mode`
  history            Alias for `hist`
  quit               Alias for `exit`
  quit-program       Alias for `exit-program`
  reload-method      Alias for `reload-code`
  show-method        Alias for `show-source`

Check for members in Ruby

Ruby’s Enumerable class has a member? method that returns a boolean.

For arrays, the method checks if the supplied value is included (similar to ['a'].include?('a')):

[:a, :b].member?(:b) # => true
[:a, :b].member?(:c) # => false

For hashes, the method checks if the supplied value is included in the keys for the hash:

{ a: 'b' }.member?(:a) # => true
{ a: 'b' }.member?(:c) # => false

Rails has an Array#exclude? method

In my vendetta against the unless expression in ruby, I came across a use case where I wanted to execute code only if an item was missing from an array.

I could easily do:

unless ['a', 'b', 'c'].include?('d')
  # do a thing

But I wanted to replace the unless with an if, which led me to wonder if there was an exclude? method for arrays in ruby.

Turns out, ActiveSupport extended the Enumerable class to introduce exactly what I was looking for!

if ['a', 'b', 'c'].exclude?('d')
  # do a thing


Swap between STI classes in Rails

Rails allows you to swap between single table inheritance classes with the becomes method. This method creates a new instance of the desired class, and passes the attributes from the original record to the new instance.

So if I have two classes, User and Admin, where Admin inherits from User:

class User
  # ...

class Admin < User
  # ...

I can change between the two classes using becomes:

user = User.first # returns an instance of the User class
user.class # => User # => 1 # => Joe Hashrocket

admin = user.becomes(Admin) # returns an instance of the Admin class
admin.class # => Admin # => 1 # => Joe Hashrocket

Remove newlines from strings in Rails

Rails has a method called squish that will remove newlines from strings. It works very nicely with heredocs, where you may want readability but don’t really want the newlines.

Without squish:

  update posts
  set status = 'public'
  where status is null;
# "update posts\nset status = 'public'\nwhere status is null;\n"

With squish:

  update posts
  set status = 'public'
  where status is null;
# "update posts set status = 'public' where status is null;"

PostgreSQL query with an array of regexes

I recently wanted to query my Postgres database by matching a column based on an array of regular expressions:

To query where the column matches all expressions in the array:

select * 
from my_table 
where my_column ilike all (array['%some%', '%words%'])

To query where the column matches at least one, but not necessarily all, of the expressions in the array:

select * 
from my_table 
where my_column ilike any (array['%some%', '%words%'])

Reversible integer to string migrations in Rails

I recently needed to convert an integer column in Rails to a string, and wanted to make sure that the migration would be reversible. I specified the up and down methods, but found that I couldn’t reverse the migration because the column type couldn’t be automatically cast back into an integer.

As it turns out, Rails allows us to specify how to cast the column with the using option:

def up
  change_column :users, :zip, :string

def down
  change_column :users, :zip, :integer, 
    using: "zip::integer"

This builds the sql:

TYPE integer
USING zip::integer

Good to go!

How to check Rails migration statuses

You can check the status of your migrations in Rails by running rails db:migrate:status

This command returns your database name, as well as a list of all your migrations, with their name and status

database: my-database-dev

Status | Migration ID | Migration Name
  up   | 201803131234 | Create users
  up   | 201803201234 | Create blogs
 down  | 201804031234 | Create posts

Postgres locale settings are inherited from OS

By default, postgres inherits locale settings from operating system, which can greatly affect sort. Comparing linux and unix, both using the locale en_US.UTF-8, we see the following sort outputs:


select name from unnest(array['No one', 'None', ' Not']) name order by name;
No one


select name from unnest(array['No one', 'None', ' Not']) name order by name;
No one

You’ll notice that on the linux system, whitespaces are ignored during sorting.

To get consistent behavior across operating systems, you can use the postgres provided C locale:

select name from unnest(array['No one', 'None', ' Not']) name order by name collate 'C';
No one