String#start_with?
str.start_with?(*prefixes) -> true or false The start_with? method tests whether a piece of text begins with a specified prefix. It accepts one or more prefixes and returns true if the string starts with any of them, otherwise false. This method is useful for validation, conditional logic, and parsing structured text. Unlike include?, which checks for substrings anywhere in the receiver, start_with? specifically looks at the beginning of the input.
The method performs an exact string match and is case-sensitive. If you need case-insensitive matching, you’ll need to convert both the text and prefix to the same case before calling start_with?.
Syntax
str.start_with?(*prefixes)
The splat operator (*) allows you to pass multiple prefixes. The method returns true if the string starts with ANY of the provided prefixes.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
prefixes | String | — | One or more string prefixes to check against. At least one is required. Can be a single string or multiple strings using the splat operator. |
Examples
Basic usage
"hello".start_with?("hel")
# => true
"hello".start_with?("world")
# => false
"hello".start_with?("hello")
# => true
When you need to test against several possible prefixes at once, start_with? accepts them as separate arguments. This is cleaner than chaining multiple start_with? calls with ||, especially when the list of prefixes might grow over time. The method returns true as soon as any prefix matches and does not check the remaining candidates.
Checking multiple prefixes
filename = "report_2024.pdf"
filename.start_with?("report", "summary", "analysis")
# => true
filename.start_with?("invoice", "receipt")
# => false
When you need to test against several possible prefixes at once, start_with? accepts them as separate arguments. This is cleaner than chaining multiple start_with? calls with ||, especially when the list of prefixes might grow over time. The check is always case-sensitive — “Ruby” and “ruby” are treated as different prefixes. When case does not matter for your use case, normalizing both sides with downcase or upcase before calling start_with? gives you a case-insensitive comparison without altering the original values.
Case-sensitive matching
"Ruby".start_with?("ruby")
# => false
"Ruby".start_with?("Ruby")
# => true
# For case-insensitive matching:
"Ruby".downcase.start_with?("ruby")
# => true
The check is always case-sensitive, so “Ruby” and “ruby” are different prefixes. When case does not matter for your use case, normalizing both sides with downcase or upcase before calling start_with? gives you a case-insensitive comparison without changing the original values.
An interesting edge case: start_with? always returns true when the prefix is an empty string, because every possible input begins with zero characters.
Empty string behavior
"hello".start_with?("")
# => true
"".start_with?("")
# => true
"".start_with?("anything")
# => false
These basic behaviors combine into practical patterns. A common use case is routing commands — you check the first few characters of user input and branch to the right handler. The pattern below uses start_with? inside an if/elsif chain to dispatch commands like “exit,” “help,” and “load.”
Common Patterns
Input validation
def process_command(input)
if input.start_with?("exit") || input.start_with?("quit")
puts "Goodbye!"
exit
elsif input.start_with?("help")
show_help
elsif input.start_with?("load ")
load_file(input[5..])
else
execute(input)
end
end
Prefix checks also work well for categorizing filenames and paths. Instead of parsing file extensions with a regex, you can test whether a filename starts with a known pattern. The example below keeps the allowed extensions in a list and checks against each one with any?.
File type checking
ALLOWED_EXTENSIONS = %w[pdf png jpg]
def allowed_extension?(filename)
ALLOWED_EXTENSIONS.any? { |ext| filename.start_with?(ext) }
end
# Usage
allowed_extension?("document.pdf") # => true
allowed_extension?("image.png") # => false
Sometimes a single prefix test is all you need. Checking whether a URL starts with https:// is a one-line guard that catches unencrypted links before they reach other code. The same pattern works for HTTP methods — keep the known method names in a list and use any? with start_with? to match the beginning of the input.
URL parsing
def secure_url?(url)
url.start_with?("https://")
end
def http_method(method)
valid_methods = %w[GET POST PUT DELETE PATCH]
valid_methods.any? { |m| method.start_with?(m) }
end
Lambdas in case statements open the door to more complex matching conditions than simple equality. The pattern below uses start_with? inside a lambda as a when condition, routing requests to different handlers based on the first segment of the path. This is cleaner than a long chain of if/elsif branches and keeps each route handler separate.
Routing logic
def route_request(path)
case path
when ->(p) { p.start_with?("/api/") }
handle_api(path)
when ->(p) { p.start_with?("/admin") }
handle_admin(path)
when ->(p) { p.start_with?("/static") }
serve_static(path)
else
handle_default(path)
end
end
Using lambdas in case statements allows for more complex matching conditions.
That pattern works well when the first part of the string determines a request category. The prefix check stays visible, but the rest of the method can branch on a few well-named handlers.
Errors
The start_with? method does not raise any exceptions under normal circumstances. However, passing nil as a prefix will raise a NoMethodError:
"hello".start_with?(nil)
# => NoMethodError: undefined method `start_with?' for nil:NilClass
Always ensure your prefix values are strings before calling start_with?.
See Also
- String#end_with? — checks if a string ends with a suffix
- String#include? — checks if a string contains a substring anywhere
- Kernel#chomp — removes trailing line separators
- String#lstrip — removes leading and trailing whitespace