robots.txt Tester for Rails Apps
Fetch the robots.txt of any site, see how it is parsed, and find out which single rule decides whether a crawler may request a given path.
This tool fetches the file from our server rather than your browser, so it works without JavaScript and reads hosts your browser could not.
public/robots.txt or a Rails route
Rails offers two honest homes for this file and they are not interchangeable. `public/robots.txt` is served straight off disk by nginx, never boots Rails, costs nothing per request and turns up in code review like any other file - which is the right answer whenever the content is fixed. A route, `get "/robots.txt", to: "robots#show", defaults: { format: :text }`, is the right answer once the content has to be computed. One trap makes the route worthless: if the action renders through the application layout, or the format is left to content negotiation, the crawler is handed a doctype and a nav bar, and something that is not `text/plain` is not a robots.txt at all. Declare the format, render a layoutless text view, and assert the content type in a request spec rather than trusting it.
One file cannot serve staging and production
A file checked into public/ is the same file in every environment, which is how staging gets indexed. Production has to invite crawlers in and staging has to keep them out, and one static file cannot say both things at once. A route can: render a view that emits `User-agent: *` and `Disallow: /` unless `Rails.env.production?`, or key the answer on `request.host` when one deployment serves several domains. Keep the production copy in a view rather than a heredoc in the controller and it stays as reviewable as the static file was. Basic auth across the whole staging host is stronger still, because it also stops whatever never asks for robots.txt in the first place.
Which rule actually decides
A crawler reads the whole file, picks exactly one group, and ignores every other group in it. It picks the group whose `User-agent` token most specifically names it, and the wildcard group applies only when no group does: a file with a `Googlebot` section and a `*` section is telling Googlebot to read the first and nothing else, including the rules it liked in the second. Inside that group the longest matching pattern wins, and when an `Allow` and a `Disallow` of equal length both match, `Allow` takes it. That is why `Disallow: /rails/` alongside `Allow: /rails/active_storage/blobs/` still lets blobs through, why a bare `Disallow: /admin` also covers `/admin/users`, and why `Disallow: /users/sign_in` leaves the rest of `/users` open.