This week in #dev (Apr 21, 2023)

thoughtbot
Edited by Matheus Richard

Welcome to another edition of This Week in #dev, a series of posts where we bring some of the most interesting Slack conversations to the public. Today we’re talking about: splitting arrays, handling deprecation warnings, and querying missing records.

A Handy Method for Splitting Enumerables

Steve Polito learned about Ruby’s Enumerable#partition. This method is useful for dividing an existing array into two separate arrays, he says.

# Before
def call(appointments)
  appointments_today = []
  appointments_next_week = []

  appointments.each do |appointment|
    if appointment.starts_at.to_date == Date.current
      appointments_today << appointment
    else
      appointments_next_week << appointment
    end
  end
end

# After
def call(appointments)
  appointments_today, appointments_next_week = appointments.partition do |appointment|
    appointment.starts_at.to_date == Date.current
  end
end

Handling Ruby Deprecation Warnings

Neil Carvalho discovers that Ruby deprecation warnings have been disabled since Ruby 2.7.2 due to an excessive number of deprecation warnings related to keyword arguments. This concerns him, and he suggests setting Warning[:deprecated] to true in spec_helper.rb and asks for other suggestions.

Summer ☀️ steps in and proposes logging warnings to an error-tracking service in production, while in development and testing, they recommend raising errors instead of relying on log messages that can be easily overlooked. It would be also important to be able to choose whether these actions apply to project code or dependencies, and selectively silence specific deprecation types or downgrade them from errors to warnings.

Querying Missing Associated Records

Rémy Hannequin seeks assistance with an ActiveRecord query to retrieve records that are missing associated records with a specific attribute. He provides an example scenario of authors and books with different languages and wants to find authors who don’t have books written in Elvish:

# This is not what Remy wants
Author
  .where.missing(:books)
  .where(books: {language: :elvish})

# That generates this SQL
SELECT * FROM "authors"
LEFT OUTER JOIN "books" ON "books"."author_id" = "authors"."id"
WHERE "books"."id" IS NULL
AND "books"."language" = "elvish"

Neil Carvalho responds with two possible approaches. If it makes sense to define a specific association for Elvish books in the Author model, Neil Carvalho suggests using Author.where.missing(:elvish_books) to query authors without associated Elvish books.

class Author
  has_many :elvish_books, -> { where(language: "elvish") }, class_name: "Book"
end

# Now this works!
Author.where.missing(:elvish_books)

If it doesn’t make sense to define a separate association, the recommendation is using a left join:

Author.left_joins('books ON books.author_id = authors.id AND books.language = "elvish"')

Thanks

This edition was brought to you by Neil Carvalho, Rémy Hannequin, Steve Polito, and Summer ☀️. Thanks to all contributors! 🎉