Basic Queries and Conditions
A controller needs "book 7", "the member with this email", "all available books over 300 pages". Each is a database query, and Active Record lets you write each one as a short Ruby expression. The skill is knowing which method to reach for and what it gives back when nothing matches.
The rule
find by id, find_by for one, where for many — and never interpolate.
Book.find(7) # one Book, or raises RecordNotFound
Book.find_by(title: "Dune") # first match, or nil
Book.where(available: true) # a relation: zero or more books| Method | Returns | When nothing matches |
|---|---|---|
find(id) |
one record | raises ActiveRecord::RecordNotFound (a 404 page) |
find_by(...) |
one record | nil |
where(...) |
a relation (list) | an empty relation |
Conditions come in three styles:
Book.where(author: "Le Guin") # hash: equality
Book.where(author: ["Le Guin", "Pratchett"]) # hash with array: IN (...)
Book.where(pages: 300..500) # hash with range: BETWEEN
Book.where(pages: 301..) # endless range: pages >= 301
Book.where("pages > ?", 300) # string with a ? placeholder
Book.where.not(available: true) # NOT
Book.where(available: false).or(Book.where(pages: ..100))where does not hit the database straight away. It builds a relation, a query-in-progress, and you can keep chaining: Book.where(available: true).where("pages > ?", 300) becomes one SQL query with AND. The query runs only when you need the rows — when you loop, call to_a, first, count or pluck(:title).
Handy extras: Book.first, Book.last, Book.take, Book.exists?(title: "Dune"), Book.pluck(:title) (an array of titles, no model objects).
The shortcut
Read the task and ask "id, one, or many?" An id from the URL → find. One thing by another attribute → find_by. A list → where. Then check how user input enters the SQL: a hash or a ? placeholder, never #{}.
Many or one?
A search returns a list, so
where.
Drills
Answer fast — trust the rule.
Book.find_by(title: "Missing") finds nothing. What do you get?
Which query is safe from SQL injection?
How many SQL queries run for Book.where(available: true).where("pages > ?", 300).to_a?
Which condition finds books with 100 pages or fewer?
What does Book.where(author: "Le Guin").pluck(:title) return?
Remember
- find by id, find_by for one, where for many — and never interpolate.
- Shortcut: id, one or many; then check how input enters the SQL.
- Trap: where returns a relation, never nil, and runs only when you use it.
