Sharing tips taken directly from my day-to-day development work. These are about rendering a collection with partials in Action View, reminder about Active Record query return values, and about pattern matching in Ruby.

Tip 1 - Action View spacer_template option

Do you know about the spacer_template option when rendering a collection using a partials? For example, if you render a collection of @books like this:

<%= render partial: @books, spacer_template: "fancy_line" %>

Adding the spacer_template option renders whatever partial you specify in between each pair of books. For the above example, we’d have a _fancy_line.html.erb in our app/views/books directory with whatever we want to render.

Note that we need to explicitly specify the key in render partial: @books. Otherwise it doesn’t work.

In general, we can skip specifying the keys partial and locals and list the values only. Like this:

<%= render "book", book: @book %>

<%# which is the same as this %>
<%= render partial: "book", locals: { book: @book } %>

Rails can infer the partial file name and location and pass in a matching local variable using conventions. But this is the case when parital and locals are the only options we need. We added a third spacer_template option above, so we need to specify partial as the key.

I came across this while reading the Action View Rails guide.

Tip 2 - Active Record find_by vs. find

With Rails Active Record, we think of Book.find(42) as a shorthand for Book.find_by(id: 42). But they are not exactly the same.

It’s good to keep in mind that:

  • find_by returns nil if no record is found
  • find throws an RecordNotFound exception if no matching book is found.
>> Book.find_by(id: 200)
  Book Load (0.1ms)  SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT ?  [["id", 200], ["LIMIT", 1]]
=> nil

>> Book.find(200)
  Book Load (0.8ms)  SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT ?  [["id", 200], ["LIMIT", 1]]
/Users/bhumi/.rbenv/versions/3.0.1/lib/ruby/gems/3.0.0/gems/activerecord-7.1.3/lib/active_record/core.rb:253:in `find': Couldn't find Book with 'id'=200 (ActiveRecord::RecordNotFound)

So find is actually equivalent to find_by!.

>> Book.find_by!(id: 200)
  Book Load (0.1ms)  SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT ?  [["id", 200], ["LIMIT", 1]]
/Users/bhumi/.rbenv/versions/3.0.1/lib/ruby/gems/3.0.0/gems/activerecord-7.1.3/lib/active_record/relation/finder_methods.rb:413:in `raise_record_not_found_exception!': Couldn't find Book with [WHERE "books"."id" = ?] (ActiveRecord::RecordNotFound)

The SQL queries generated by find, find_by, and find_by! is the same:

SELECT "books".* FROM "books" WHERE "books"."id" = ? LIMIT ?  [["id", 200], ["LIMIT", 1]]`. 

Tip 3 - Ruby pattern matching

Did you know that Ruby has pattern matching? It was introduced in Ruby 2.7 as an experimental feature. As of Ruby 3.1 the experimental warning is removed and is fully supported.

There are two forms. One is a modified case statement with in clauses. The other syntax is using =>. Here are some examples:

# With the `case` `in` pattern matching
?> case [1, 2, 3, 4, 5]
?> in [*pre, 2, 3, *post]
?>   p pre
?>   p post
>> end

[1]
[4, 5]

# With the => one line pattern matching
>> config = {db: {user: 'admin', password: 'abc123'}}

>> config => {db: {user:}}
>> user
=> "admin"

>> config => {db: {user: rename_user}}
>> rename_user
=> "admin"

I’m not sure if Ruby’s pattern matching is inspired by Elixir’s, which looks a little cleaner with the |.

>> [head | tail] = [1, 2, 3]

>>head
1
>>tail
[2, 3]

One common use case in the documentation is around parsing complex JSON structures. I have yet to use it or see it in an application.