โ† Back to list

Adding a User Search Feature in Rails with LIKE Queries ๐Ÿ”

In my last post, I built a friend feature for my finance tracker app using a self-referential association so users can see what theirโ€ฆ

Sam's Coding Everyday ยท 2026-05-29 20:51 ยท 0 claps ยท 1.8 min read
#ruby-on-rails #rails #activerecord #web-development #programming
Open on Medium โ†—
Wiki topics: ๐Ÿ’ป ยท Programming ๐ŸŒ ยท Web Development ๐Ÿ”’ ยท Cybersecurity

Adding a User Search Feature in Rails with LIKE Queries ๐Ÿ”

In my last post, I built a friend feature for my finance tracker app using a self-referential association so users can see what their friends are investing in. ๐Ÿ“ˆ

But there was one thing missing: before you can add a friend, you have to find them first. ๐Ÿค”

So this post is about the feature that powers that. Letting users search for other users by name or email. And this time I did most of the work in the Rails console before writing a single line in the app.

Two ways to pass conditions to where

Hash condition for exact match:

User.where(email: 'samkim5869@example.com')
# โ†’ WHERE "users"."email" = '...'

String condition when you need patterns:

User.where("email like ?", 'samkim5869@example.com')
# โ†’ WHERE (email like '...')

Same value, same result. But the string form unlocks like. like is a SQL keyword, and Rails just hands the SQL inside that string straight to the database.

The % wildcard = "anything goes here"

User.where("first_name like ?", "Han%")   # starts with Han
User.where("first_name like ?", "%saem")  # ends with saem
User.where("first_name like ?", "%ansa%") # contains ansa

No % means exact match. With % it's partial. Really handy for filtering by domain:

User.where("email like ?", "%@example.com")
# โ†’ everyone whose email ends in @example.com

Building the search, piece by piece ๐Ÿ—๏ธ

A generic engine: matches

def self.matches(field_name, param)
  where("#{field_name} like ?", "%#{param}%")
end

The self. makes it a class method so it's called as User.matches(...). Passing field_name as an argument means it can search any column.

The final window: search

def self.search(param)
  param.strip!
  first_name_matches(param)
    .or(last_name_matches(param))
    .or(email_matches(param))
end

strip! cleans whitespace off the search term (! means it mutates the original). .or Merges the three column searches into one result. So whatever the user types gets matched across first_name, last_name, or email. ๐ŸŽฏ

Verifying in the console โœ…

User.search('@').count
# โ†’ first_name like '%@%'
# โ†’ last_name  like '%@%'
# โ†’ email      like '%@%'
# => 3

Three queries fired, .or merged them, count came back. Logic confirmed before touching the app.

The takeaway: console then model then view

Last time I followed route โžก๏ธ controller โžก๏ธ view to build the friends page. This time the same discipline applied one layer earlier.

Skipping the console means: write code, boot server, open browser, type something, click, check, itโ€™s wrong, fix it, repeat. Too many steps per check, and when something breaks you canโ€™t tell if the query, the controller, or the view is at fault.

The console is one line = instant answer. It isolates the query logic so:

  1. Console proves the query is correct
  2. Model / controller is just wiring it up
  3. View is just displaying it

When a bug shows up later, the scope is already narrow. Itโ€™s like tasting the dish as you cook instead of plating everything and then realizing itโ€™s too salty. ๐Ÿณ


๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
post_id
14514f5754a6
slug
adding-a-user-search-feature-in-rails-with-like-queries-14514f5754a6
url
https://medium.com/@samkim5869/adding-a-user-search-feature-in-rails-with-like-queries-14514f5754a6
canonical_url
https://medium.com/@samkim5869/adding-a-user-search-feature-in-rails-with-like-queries-14514f5754a6
author_url
https://medium.com/@samkim5869
status
ok
fetched_at
2026-06-09 15:37:30