Ruby on Rails flashcards: request to production
Recall cards for each Rails 8.1 lesson: requests, Active Record, routing, views, Hotwire, accounts, jobs, tests, APIs, security, caching and deploys.
406 cards. Read the question, answer it in your head, then open the card to check.
-
Between Puma and your controller action, what does a request go through in a Rails app, in order?
Puma builds a Rack env and calls Rails.application. The env goes down the middleware stack, the router matches its method and path against config/routes.rb, and Rails creates the controller and calls the action. The response climbs back up through the same middleware before Puma sends it.
From the lesson How Rails handles a request
-
A middleware layer answers a request itself. Which layers are skipped, and which see its response?
Every layer below it is skipped. Only the layers above it see the response, since the stack is walked from the top on the way in and from the bottom on the way out.
From the lesson How Rails handles a request
-
How many middleware does a new Rails 8.1 app run in development, and how many in production?
28 in development and 21 in production. The extra development layers reload code, serve the console and stop mistakes early; production keeps what every request needs and enforces SSL only once config.force_ssl is switched on.
From the lesson How Rails handles a request
-
Two routes in config/routes.rb match the same request. Which one runs, and in what form do the request's values reach params?
The route listed first wins. Values from the path, the query string and a form all arrive in params as strings.
From the lesson How Rails handles a request
-
A controller action finishes without calling render or redirect_to. What does Rails send back?
The template that carries the action's name, so the show action renders its show view.
From the lesson How Rails handles a request
-
What does the Rails doctrine mean by an omakase stack?
The default stack that comes with Rails' frameworks, from Active Record to Action Cable: its parts are chosen to work together, and any one of them can still be replaced.
From the lesson How Rails handles a request
-
What kind of project suits Rails best, and what most often points a team elsewhere?
One team building a product on a database, with pages and background work. The team's language, or a decision to build the front end in React, are the usual reasons to choose something else.
From the lesson How Rails handles a request
-
In what order do you install Ruby and Rails for a project, and how do you confirm both?
Ruby first, through a version manager such as mise, then the rails gem with its version stated. ruby --version and rails --version show what you got.
From the lesson Install Rails 8.1 and create your first app
-
What does rails new do after it writes the app's files?
It runs bundle install, adds the Linux platforms to Gemfile.lock and then runs the installers of its chosen gems: import maps, Turbo, Stimulus, Kamal and the Solid libraries. With --skip-bundle it stops after the files, and every installer is skipped as well.
From the lesson Install Rails 8.1 and create your first app
-
Why pick --database, --javascript and --css when you run rails new instead of changing them later?
They shape the Gemfile and the configuration before any of your own code exists. Choose them for the production you intend to run, rather than converting a working app afterwards.
From the lesson Install Rails 8.1 and create your first app
-
Where do your code, settings, schema, tests and command scripts live in a new Rails app?
Code in app/, settings in config/, the schema in db/, tests in test/ and commands in bin/. The key file that decrypts the credentials is kept out of the repository.
From the lesson Install Rails 8.1 and create your first app
-
What does bin/setup do, and why can you run it again at any time?
It installs gems the bundle lacks, prepares the database with db:prepare, clears old logs and temporary files and starts the server. Gems are installed and the database created or migrated only when something is missing, so running it again is safe.
From the lesson Install Rails 8.1 and create your first app
-
Which command serves a new app in development, and how can you tell it is up?
bin/dev starts Puma. The /up path answers with status 200 once the app runs.
From the lesson Install Rails 8.1 and create your first app
-
Which command lists the Rake tasks your own app defines, beside the built-in ones?
bin/rails -T. bin/rails --help shows the common commands and their aliases first.
From the lesson The Rails command line, console and generators
-
How do you preview the files a generator would write, and how do you remove them again?
Add --pretend to print the list without writing anything. bin/rails destroy with the same arguments deletes the files; roll back its migration first if it already ran.
From the lesson The Rails command line, console and generators
-
In bin/rails generate model, what do the field modifiers string! and :uniq become?
string! makes the column null: false, so the database refuses an empty value; :uniq adds a unique index. The migration's t.timestamps line adds created_at and updated_at.
From the lesson The Rails command line, console and generators
-
You add a column to a scaffolded model weeks later. Does its form show the new field?
No. A scaffold writes its model, eight routes, controller and views a single time; a later column reaches the form and the permitted list of params.expect only when you add it by hand.
From the lesson The Rails command line, console and generators
-
What happens to the rows you create in bin/rails console --sandbox?
They disappear when you leave, because the sandbox wraps the whole session in a transaction it never commits. Scripts run with runner or a Rake task keep their changes.
From the lesson The Rails command line, console and generators
-
Which files does bin/rails generate model Teacher write, and when does the database change?
A migration under db/migrate, the model under app/models, a model test and a fixtures file. The database changes only when bin/rails db:migrate runs.
From the lesson The Rails command line, console and generators
-
From the model name Batch, which other names does Rails work out?
The table batches, the foreign key batch_id, the controller BatchesController and the views folder batches, all through the inflector and with no configuration.
From the lesson Conventions, autoloading and Zeitwerk
-
Which constant must the file app/services/fees/receipt_builder.rb define?
Fees::ReceiptBuilder. Below the autoload root, each folder becomes a module and the file name becomes the class.
From the lesson Conventions, autoloading and Zeitwerk
-
Why can a misnamed file work in development and still stop a production boot?
Development loads a constant only when code first uses it, so an unused file is never read. Production eager-loads every file at boot, where the wrong constant raises Zeitwerk::NameError.
From the lesson Conventions, autoloading and Zeitwerk
-
What does bin/rails zeitwerk:check report?
It loads the app the way production does and names the first file that defines a different constant from the one its path names, before a deploy finds it.
From the lesson Conventions, autoloading and Zeitwerk
-
A class is named PDFReceipt. What does Zeitwerk need before it can load it?
An inflect.acronym entry for PDF, or the class renamed to the spelling the inflector already gives, PdfReceipt.
From the lesson Conventions, autoloading and Zeitwerk
-
Where does boot code go that configures your app's own classes?
Inside a to_prepare block. Initializers run once, before those classes can autoload; to_prepare runs at boot and again after each reload.
From the lesson Conventions, autoloading and Zeitwerk
-
A page returns 500 in development. What do you read first, and in what order?
The log entry of that request, in log/development.log or the bin/dev terminal: the Completed 500 line, the exception with its first line inside app/, then the parameters and the SQL just above it. Open the code only after that.
From the lesson Debugging Rails apps
-
Which values does filter_parameters hide, and which does it still write to the log?
It hides any parameter whose name contains a listed word, in any letter case. A name not on the list, a secret placed in a URL path and anything your own code logs are written in full.
From the lesson Debugging Rails apps
-
Why choose find_by! over find_by when the row has to exist?
find_by hands back nil for a missing row, and the crash comes later in some other line. find_by! raises a not-found error at once, which production answers with a 404.
From the lesson Debugging Rails apps
-
What do verbose query logs and query log tags add to your view of SQL?
Verbose query logs print the line of your code below each query in the development log. Query log tags append a comment naming the controller and action to the SQL itself, so the database's own logs can point back to the code.
From the lesson Debugging Rails apps
-
How do you stop a test, the server or the console at one line to look at its values?
Put a debugger call there, from the debug gem. Execution pauses at that line, and info locals lists the local variables.
From the lesson Debugging Rails apps
-
A request fails in production. What does the visitor get, and where are the details?
The generic public/500.html page, because production sets consider_all_requests_local to false. The exception, the failing line and the parameters stay in the log, and Web Console exists only in development, for localhost alone.
From the lesson Debugging Rails apps
-
A form sends "22" for the integer column seats. What does the model hold after assignment?
The Integer 22. Active Record reads the column types from the database and casts each value the moment it is assigned to the attribute.
From the lesson Active Record models and CRUD
-
What do find, find_by and where each give back when nothing matches?
find raises ActiveRecord::RecordNotFound, which Rails turns into a 404. find_by returns nil. where returns an empty, lazy relation that sends no SQL until something asks for its rows.
From the lesson Active Record models and CRUD
-
How do save and save! behave on an invalid record, and where does each belong?
save returns false and fills errors, so a controller can show the form again with the messages. save! raises ActiveRecord::RecordInvalid, so a job, a seed or a script stops at the first bad row. Both run validations and callbacks and touch updated_at.
From the lesson Active Record models and CRUD
-
What do update_columns and update_all leave out, and when is that acceptable?
They skip validations and callbacks and leave updated_at untouched. Use them only on data your own code controls, never on values that came from a user.
From the lesson Active Record models and CRUD
-
How does destroy differ from delete on a record?
destroy loads the row first and runs callbacks and the dependent: rules of its associations. delete sends one DELETE with none of that, so it suits only a row with no associations and nothing to clean up.
From the lesson Active Record models and CRUD
-
Which methods tell you what changed on a record before a save, and which after it?
Before the save, changed? and changes. After it, saved_change_to_<attribute>? and previous_changes.
From the lesson Active Record models and CRUD
-
How does db:migrate decide which migrations to run?
It runs, in version order, every migration whose version is missing from the schema_migrations table, then rewrites db/schema.rb to match the database. db:rollback undoes the newest one, and db:migrate:status lists each as up or down.
From the lesson Migrations and the database schema
-
A change migration contains change_column. What happens on rollback, and how do you fix it?
Rollback raises ActiveRecord::IrreversibleMigration, because Rails cannot know the old column definition. Describe the way back with a reversible block or with separate up and down methods.
From the lesson Migrations and the database schema
-
What do db:prepare, db:reset and db:seed:replant do to existing data?
db:prepare creates and loads a database that does not exist yet, or runs the pending migrations of one that does. db:reset and db:seed:replant both delete rows before seeding again.
From the lesson Migrations and the database schema
-
Which schema rules make the database itself refuse a bad row, whatever code writes it?
null: false on a column, unique indexes, foreign keys and check constraints. A violation comes back as an exception such as ActiveRecord::RecordNotUnique.
From the lesson Migrations and the database schema
-
When should an app keep db/structure.sql instead of db/schema.rb?
Only when the database holds something the migration DSL cannot express, such as triggers, sequences or stored procedures. New databases are built from the schema file, so it has to describe all of it.
From the lesson Migrations and the database schema
-
A migration has already run on a teammate's machine or in production, and it needs a change. What do you do?
Leave it exactly as it was and write a new migration. Every database runs each version once, so an edited old file never reaches the databases that already ran it.
From the lesson Migrations and the database schema
-
A validation fails during save. What happens, and where do you read the result?
Nothing is written and save returns false; no exception is raised. errors.full_messages gives the sentences for the user, errors.details the symbols for translation.
From the lesson Validations, errors and normalization
-
How can one model hold the light checks of a draft and the stricter checks of a finished record?
With contexts: on: :create, on: :update or a custom context name decides which rules run for a given save or valid? call.
From the lesson Validations, errors and normalization
-
When does a normalizes rule run, and does it replace validation?
It runs when the value is assigned and when the attribute is used in a query, so values are stored and searched in one shape. Validations still run afterwards, on the cleaned value.
From the lesson Validations, errors and normalization
-
Why can two rows with the same value appear despite a uniqueness validation?
The validation is a SELECT just before the INSERT, not a lock. Two requests at the same moment may each see no such row and each insert one. A unique index stops the second row; rescue ActiveRecord::RecordNotUnique to show a clean message.
From the lesson Validations, errors and normalization
-
How do you add a rule that Rails has no built-in validator for, or one that applies only sometimes?
Write it with validate :method_name or an ActiveModel::Validator class, and gate it with if: or unless:. Accept values from a known-good list rather than trying to list the bad ones.
From the lesson Validations, errors and normalization
-
An enum attribute is set from user input. How do you get an error message instead of an exception for an unknown value?
Declare the enum with validate: true; an unknown value then becomes a validation error on the record.
From the lesson Validations, errors and normalization
-
Why does saving a new batch without a teacher fail in a Rails 8.1 app?
belongs_to adds a validation that the parent exists. Add optional: true only where a missing parent is a state you mean to allow.
From the lesson Associations
-
When must you write inverse_of on an association?
When an option such as foreign_key stops Rails from pairing the two sides itself; without it, a child loaded through its parent fetches a second copy of that parent.
From the lesson Associations
-
When do you prefer a join model with has_many :through over has_and_belongs_to_many?
As soon as the link carries anything beyond two ids, such as a join date or an agreed fee. A join model can hold those columns, validate them, run callbacks and be queried on its own.
From the lesson Associations
-
What do dependent: :destroy, :delete_all and :restrict_with_error do to a parent's children?
destroy loads each child and runs its callbacks, so deletes cascade further down. delete_all removes the children in one statement and leaves their own dependents behind. The restrict options refuse the delete while any child exists.
From the lesson Associations
-
What can leave a counter cache column wrong, and how do you repair it?
Any write that skips callbacks, such as insert_all or upsert_all, because the column is kept in step by the child's callbacks. reset_counters recounts it.
From the lesson Associations
-
How do a polymorphic belongs_to and delegated_type differ?
A polymorphic belongs_to lets one table, such as comments, point at several parent models through a type and an id, which no foreign key can check. delegated_type keeps the shared columns of several kinds of record in one table, with each kind's own columns in its own table, so a mixed feed can be ordered and counted in one place.
From the lesson Associations
-
How does Rails 8.1 help you retire an association without breaking its callers?
Mark it deprecated: true. Each use, including indirect ones such as a preload, is reported with its location, so the callers can be fixed before you delete it.
From the lesson Associations
-
When does a chain of where, order and joins send its SELECT?
Only when a loader asks for rows or a value: first, to_a, pluck, count, find_each and the like. Until then the relation is a plan that more calls can extend.
From the lesson Querying: relations, scopes and calculations
-
How do you see the SQL a relation will send, and the database's plan for it?
to_sql returns the SQL text without running it. explain asks the database for its plan; in Rails 8.1 it returns an ExplainProxy that prints the plan when you pp it.
From the lesson Querying: relations, scopes and calculations
-
Which methods compute numbers in the database instead of loading rows into Ruby?
count, sum, average, minimum, maximum and group(...).count, which return one value or one per group. pluck and pick read columns without building objects, and exists? answers yes or no.
From the lesson Querying: relations, scopes and calculations
-
How do you walk a table of a million rows without loading them all into memory?
With find_each or in_batches, which read the table one page at a time.
From the lesson Querying: relations, scopes and calculations
-
How do you hand user input to where and order without opening a SQL injection hole?
Give where a hash, a Range, ? placeholders or named binds, never interpolated text. Escape LIKE patterns with sanitize_sql_like, and check a sort column from params against an allowlist.
From the lesson Querying: relations, scopes and calculations
-
Why should a filter be a scope rather than a class method that may return nil?
A scope always returns a relation, even when its condition is skipped, so filters keep chaining into one SELECT. A class method that returns nil in one branch breaks every caller that chains after it.
From the lesson Querying: relations, scopes and calculations
-
In what order do the callbacks of a save run?
before_validation, after_validation, before_save, before_create or before_update, after_create or after_update, after_save, and finally after_commit or after_rollback. The order is fixed, whatever order the model declares them in.
From the lesson Callbacks, enums, JSON and custom types
-
A saved payment must trigger a receipt email. Why send it from after_commit rather than after_save?
after_save runs inside the transaction, so an email started there still goes out if the save later rolls back. after_commit runs only once the change is permanent and visible to other connections.
From the lesson Callbacks, enums, JSON and custom types
-
What does throw :abort in a before_save callback do?
It stops the save, and save returns false with no error message unless the callback adds one to errors first.
From the lesson Callbacks, enums, JSON and custom types
-
Why declare an enum with string values rather than with an array?
Strings store readable words, so rows read in SQL or by another app make sense as they are. An array stores each value's position: a new value may only go at the end, and anyone reading the rows outside the app needs the model's mapping. Either way you get predicates, bang methods and scopes for each value.
From the lesson Callbacks, enums, JSON and custom types
-
How do store_accessor and serialize differ for settings kept in one column?
store_accessor reads and writes chosen keys of a JSON column, without casting them. serialize with coder: JSON keeps a whole object in a text column. YAML or Marshal coders do not belong on data that users can change.
From the lesson Callbacks, enums, JSON and custom types
-
What does a custom attribute type such as PaiseType do for a fee entered as rupee text?
It casts the text to whole paise through BigDecimal, and queries go through the same cast. Validate the cast value with presence and comparison: numericality looks at the text the person typed, so it refuses an amount written with the currency sign.
From the lesson Callbacks, enums, JSON and custom types
-
Which actions does resources :batches declare, and on how many URL shapes?
index, new, create, show, edit, update and destroy, on four shapes: /batches, /batches/new, /batches/:id and /batches/:id/edit. The verb tells the actions on one shape apart, and update answers both PATCH and PUT.
From the lesson Routing: resources and RESTful URLs
-
How does a singular resource such as resource :session differ from resources?
It declares no index action and leaves the :id segment out of every path.
From the lesson Routing: resources and RESTful URLs
-
What does shallow: true change in a nested resource?
Routes that list or create children keep the parent in the URL, such as /batches/7/enrollments, while routes for one existing child get their own short URL, such as /enrollments/31. Nest one level at most.
From the lesson Routing: resources and RESTful URLs
-
How does namespace :admin differ from scope "(:locale)" in routes.rb?
A namespace moves the path, the helper names and the controller into a module. A scope like "(:locale)" changes only the path.
From the lesson Routing: resources and RESTful URLs
-
A custom route declared below resources :batches never reaches its action. Why, and what fixes it?
The router takes the first route that fits, and show's /batches/:id fits first. Declare the custom route above resources, or give show a constraint, such as ids made only of digits, so it refuses the request.
From the lesson Routing: resources and RESTful URLs
-
How do you add an odd action to a resource, and how do you keep an old URL working?
Add a member route for one record or a collection route for the list, with the verb that matches what it does. A redirect in routes.rb sends old links on with a 301 unless you give another status.
From the lesson Routing: resources and RESTful URLs
-
When do you need batch_url rather than batch_path?
For anything read outside the current page, such as an email. A path is enough inside a page the browser already has; URL helpers take their host from default_url_options.
From the lesson Routing: resources and RESTful URLs
-
In what types do request values reach params?
As strings when they come from the path, the query string or a form; only a JSON body keeps its own numbers and booleans. Turning them into numbers and dates is the model's job, through its column types.
From the lesson Controllers, params and strong parameters
-
What does params.expect(batch: [:name, :seats]) check that require(...).permit(...) does not?
The shape as well as the keys. A body whose batch is not a hash gets 400 Bad Request, where require and permit raised a 500 on the same input.
From the lesson Controllers, params and strong parameters
-
A form sends a key that the filter does not name. What happens to it?
It is left out of the filtered params without a word. action_on_unpermitted_parameters can log or raise for permit, but a filter written with expect reports nothing, so a renamed field shows up only in tests or the log.
From the lesson Controllers, params and strong parameters
-
Strong parameters and model validations both look at input. Why does an app need both?
Strong parameters decide which keys may reach the model at the HTTP boundary; validations check the values those keys carry.
From the lesson Controllers, params and strong parameters
-
Which statuses does a scaffolded controller send after a failed save and after a successful change?
422 when the save fails and the form is rendered again, and a 303 redirect after a change, which is what Turbo expects from a form submission.
From the lesson Controllers, params and strong parameters
-
How does one action answer HTML, JSON and Turbo Stream requests, and how do errors become statuses?
respond_to runs the block for the format the request asks for and sets its content type. find already means 404 for a missing record, and rescue_from turns your own domain errors into the status and body a client should see.
From the lesson Controllers, params and strong parameters
-
Where does the default session store keep a session, and what limits follow from that?
In one encrypted cookie in the browser. Rails can trust what comes back but can never take back a copy it sent, and a session over 4,096 bytes raises CookieOverflow, so keep only small values that are safe to replay.
From the lesson Sessions, cookies, flash and Current
-
What can a user do with a plain, a signed and an encrypted cookie?
Read and change a plain one, read but not change a signed one, and neither read nor change an encrypted one. Both protected jars depend on secret_key_base staying private.
From the lesson Sessions, cookies, flash and Current
-
When do Rails cookies get the Secure flag, and how long does permanent ask for?
Secure comes with config.force_ssl, which also redirects HTTP and sends HSTS. permanent asks for 20 years, while browsers that follow the cookie draft keep a cookie 400 days at most, so a lifetime in days with checks on the server is safer.
From the lesson Sessions, cookies, flash and Current
-
How does the generated authentication make signing out stop an old copy of the cookie?
The signed cookie only names a row of the sessions table. Signing out destroys the row, so a copied cookie then names nothing. Code that keeps a user id in the session instead calls reset_session when privileges change.
From the lesson Sessions, cookies, flash and Current
-
When do you set flash, and when flash.now?
flash lasts until the next request, so it suits a redirect; flash.now shows the message on the current render only. With Turbo, a failed form answers 422 with its message in the body.
From the lesson Sessions, cookies, flash and Current
-
Why does a background job not see the Current.user of the request that enqueued it?
Current holds one request's context on its own thread, and Rails empties it when each request and each job ends. Give the job what it needs as an argument, or let it read a record.
From the lesson Sessions, cookies, flash and Current
-
In what order do controller filters run, and what still runs after a before_action redirects?
In the order they are declared. A filter that renders or redirects skips the action and every after_action, but an around_action that started earlier still runs its lines after yield.
From the lesson Filters, errors and HTTP features
-
What is allow_unauthenticated_access in a generated app, and what happens when a skip names a filter that is not there?
It is skip_before_action :require_authentication from the generated concern. A skip that names a filter missing from the chain raises an error rather than passing quietly.
From the lesson Filters, errors and HTTP features
-
What turns ActiveRecord::RecordNotFound into a 404, and what maps your own exceptions?
config.action_dispatch.rescue_responses already maps Rails' own exceptions, so RecordNotFound becomes 404 with no handler of yours. rescue_from maps the exceptions of your domain to responses.
From the lesson Filters, errors and HTTP features
-
Why did a rate limit let all twelve sign-in attempts through in the test environment?
rate_limit counts in the cache store its class picked up at boot, and the generated test environment uses :null_store, which keeps no counts. A test of the limit has to configure a store that does, such as a memory store.
From the lesson Filters, errors and HTTP features
-
What does allow_browser versions: :modern do with an old browser, and with a request that sends no user agent?
An old browser, such as Chrome 100, gets status 406 and a static page from public. A current browser is served, and so is a request with no user agent at all.
From the lesson Filters, errors and HTTP features
-
What do a conditional GET and no_store each do for a page?
A conditional GET answers 304 with no body when the page has not changed since the client's copy, so the page is built only once. no_store tells every cache that obeys the header not to keep the response, as a fee page or a receipt needs.
From the lesson Filters, errors and HTTP features
-
An action renders nothing. Which template does Rails look for, and where does it search before it raises?
The template named after the controller and the action, for the request's format. If that is missing, Rails walks up the controller's parent classes, through app/views/application, before raising an error.
From the lesson ERB views, layouts, partials and helpers
-
Why can a layout show a page title that its template set with content_for?
The template renders first and the layout second. The plain yield takes the body and a named yield takes what content_for collected. Rails picks the layout by the controller's name, then falls back to layouts/application.html.erb.
From the lesson ERB views, layouts, partials and helpers
-
What does a strict-locals line at the top of a partial change?
A local it lists without a default becomes required, one with a default may be left out, and a name it does not list, such as a misspelling, raises ActionView::StrictLocalsError instead of rendering a page with a value silently missing.
From the lesson ERB views, layouts, partials and helpers
-
What does render @batches do?
It renders the _batch partial once for each record, with the record in a local named batch and its position, from 0, in batch_counter. An empty collection makes render return nil, so a fallback text can follow it after ||.
From the lesson ERB views, layouts, partials and helpers
-
The <%= %> tag escapes what it prints. Which three ways of printing skip that?
raw, the <%== %> tag and a string marked with html_safe. In the recorded run only the raw version let a script element into the page, so none of the three may carry text a person typed.
From the lesson ERB views, layouts, partials and helpers
-
Which helper should a state change such as a delete use, and which helper builds the ids Turbo expects?
button_to, which writes a small form that sends a non-GET request; link_to with a route helper stays for plain navigation. dom_id builds the element ids that forms and Turbo already look for.
From the lesson ERB views, layouts, partials and helpers
-
What does form_with model: @payment work out from the record?
The method, the URL, the field names such as payment[student_name] and the CSRF token. A new record posts to the collection, and a saved one sends PATCH to its own URL.
From the lesson Forms with form_with
-
Why does f.check_box write a hidden field just before the box?
An unticked box sends nothing at all, so the hidden 0 makes sure the controller still receives a value for it.
From the lesson Forms with form_with
-
Why re-render an invalid form with status 422 rather than 200?
Turbo reads the status. A 2xx counts as success, so the form with its errors would be dropped; a 4xx makes Turbo swap the form in place, keeping what the user typed. Rails 8.1 names the status :unprocessable_content, and a successful change redirects with 303.
From the lesson Forms with form_with
-
Which two attributes link a field to its error message for assistive technology?
aria-invalid="true" on the field, and aria-describedby pointing at the element that holds the message. A request test can check both without a browser.
From the lesson Forms with form_with
-
How can a page send a delete without a GET request?
button_to writes a CSRF-protected form that works even without JavaScript; link_to with data turbo_method set to delete lets Turbo send the DELETE.
From the lesson Forms with form_with
-
What does accepts_nested_attributes_for :guardians, allow_destroy: true give a Student model?
A guardians_attributes= writer that creates, updates and removes guardians inside the student's own save. In the view, fields_for writes one indexed group of fields per guardian, with a hidden id for every saved one.
From the lesson Nested forms and custom form builders
-
How do you accept nested guardian fields with params.expect?
Name them as guardians_attributes: [[...]], with double brackets. That keeps the index-keyed hash the form sends and drops keys you did not name; the request gets 400 only when the top-level key is missing or not a hash.
From the lesson Nested forms and custom form builders
-
A nested form adds two guardians, and the second has an invalid phone. What gets saved?
Nothing. update validates the student and every guardian before it writes, so one invalid child means ROLLBACK, status 422 and no rows. When everything is valid, removals are sent first and the other writes after them, in one transaction.
From the lesson Nested forms and custom form builders
-
A crafted request puts the id of another student's guardian into a nested form. What happens?
Nested attributes look every id up among this student's own guardians, so the foreign id raises RecordNotFound. Code written by hand has to do the same, through @student.guardians.find(id).
From the lesson Nested forms and custom form builders
-
How are new guardian rows added on the page, and how are saved ones removed?
A Stimulus controller copies a template element and gives each copy an index that is unique and made of digits. Saved rows are removed with the _destroy box, which needs no JavaScript.
From the lesson Nested forms and custom form builders
-
Why does collection_check_boxes send a hidden empty value, and what does a FormBuilder subclass give an app?
With every box unticked nothing would be sent, so the list could never be cleared. A FormBuilder subclass set as default_form_builder writes every field with the same accessible markup. A file field, for its part, makes the whole form multipart.
From the lesson Nested forms and custom form builders
-
What does include ActiveModel::API give a plain Ruby class?
Naming, conversion, attribute assignment and validations, so form_with and the error helpers accept it with no table behind it. ActiveModel::Attributes adds typed fields with defaults.
From the lesson Active Model and form objects
-
What does normalizes do in an Active Model class, and what must hold for its block?
Since Rails 8.1 it cleans a value into one shape as it is assigned, and a separate validation decides whether that shape is acceptable. Running the block a second time on its own output must change nothing.
From the lesson Active Model and form objects
-
How should a form object's save write the three records one screen creates?
Check every rule first, then write each record with save! inside one transaction. A refused write raises, the rollback removes the rows written before it, and save returns false with a message.
From the lesson Active Model and form objects
-
What does render markdown: with a plain object send, and what does a request for an unlisted type get?
Whatever the object's to_markdown returns, as text/markdown; Rails 8.1 knows the md format without an initializer. A request for a type the action does not list gets 406.
From the lesson Active Model and form objects
-
Where are a form object's rules tested, and where is its rollback shown?
The rules in plain Ruby, with no server, browser or database. The rollback happens in the database, so it is shown against a real one.
From the lesson Active Model and form objects
-
What checks a partial's locals when it declares no strict locals?
Nothing. A misspelt local silently vanishes, and each state of the partial can be tested only by rendering a whole page around it.
From the lesson View components, presenters and Phlex
-
What is a presenter, and what should its methods return?
A plain Ruby object that formats one record for display and can be tested without the app running. It returns strings, never markup.
From the lesson View components, presenters and Phlex
-
How is a ViewComponent built and tested?
It is a class with its template beside it: initialize checks the arguments, and the template runs with the component as self. render_inline tests and preview classes show each state on its own.
From the lesson View components, presenters and Phlex
-
How does Phlex write a view?
As a Ruby class whose methods produce the HTML, one call per element. phlex-rails lets render take such a class the way it takes a partial or a component.
From the lesson View components, presenters and Phlex
-
Do partials, ViewComponents and Phlex views escape their output?
All three escape by default, and each has one explicit way around it, such as raw, html_safe or Phlex's raw(safe(...)). That way must never carry text a person typed.
From the lesson View components, presenters and Phlex
-
When does a presenter beat a helper?
When a formatting rule belongs to one kind of record and deserves its own tests. A helper is mixed into every view and suits a small piece of markup used everywhere, such as a link with an icon.
From the lesson View components, presenters and Phlex
-
Why can Propshaft's asset files be cached for a year?
Each file is served under a name that ends in a hash of its contents, so changed contents get a new URL and an old name never points at new contents.
From the lesson Assets: Propshaft, import maps and CSS
-
What does bin/rails assets:precompile do for production?
It writes every digested file once, together with a manifest through which Rails finds the digested name of each asset.
From the lesson Assets: Propshaft, import maps and CSS
-
What is an import map, and what does pin_all_from save you?
JSON in the page head that maps each module name, such as @hotwired/turbo-rails, to a digested file, so modules import each other by name with no bundler. pin_all_from adds a whole folder, such as the Stimulus controllers, without a line for each file.
From the lesson Assets: Propshaft, import maps and CSS
-
Which pins does bin/importmap audit check, and what covers Turbo and Stimulus in a new app?
Only pins that carry a version comment. A new app's Turbo and Stimulus pins come from gems, which bin/bundler-audit checks.
From the lesson Assets: Propshaft, import maps and CSS
-
After a JavaScript change, why can a page keep answering 304 with yesterday's scripts?
Its ETag does not change when only the JavaScript does. stale_when_importmap_changes, which the generated ApplicationController calls, mixes the import map's digest into the ETag.
From the lesson Assets: Propshaft, import maps and CSS
-
How does a nonce-based Content Security Policy decide which scripts run?
Tags that carry this response's nonce, such as the import-map tags, run, and a script without it is refused. Each response needs a fresh nonce of its own.
From the lesson Assets: Propshaft, import maps and CSS
-
When do you add jsbundling-rails, tailwindcss-rails or cssbundling-rails?
jsbundling-rails when code needs compiling, such as JSX or TypeScript; tailwindcss-rails for Tailwind without Node.js; cssbundling-rails for a CSS build that runs on Node.js.
From the lesson Assets: Propshaft, import maps and CSS
-
What does Turbo Drive do with a link click?
It turns the click into a visit: it fetches the page in the background, swaps in the response's body and merges its head, so assets that did not change are never parsed again.
From the lesson Turbo Drive and Turbo Frames
-
How do advance and replace visits treat the browser's history?
An advance visit adds a history entry and a replace visit overwrites the current one. Back and Forward restore a page from Turbo's cache.
From the lesson Turbo Drive and Turbo Frames
-
Which answers does a form submitted through Turbo need, and which answer will Turbo not follow?
A 303 redirect after a successful save, which Turbo follows with a fresh GET so a reload never resubmits, and 422 when validation fails, which Turbo renders in place. A plain 200 to a non-GET submission is the one answer it will not navigate to.
From the lesson Turbo Drive and Turbo Frames
-
What do data-turbo="false" and data-turbo-track="reload" do?
data-turbo="false" hands a link or form back to the browser. data-turbo-track="reload" on a versioned asset forces a full page load when that asset changes. Since Turbo 8, links also prefetch on hover by default.
From the lesson Turbo Drive and Turbo Frames
-
A link inside a Turbo Frame is clicked. What must the response contain?
A turbo-frame with the same id; Turbo takes that frame from the response and leaves the rest of the page alone. target="_top" sends the navigation to the whole page, and data-turbo-action="advance" also updates the URL.
From the lesson Turbo Drive and Turbo Frames
-
When does a frame with src fetch its content, and what does loading="lazy" change?
Without it the frame loads together with the page. With loading="lazy" it waits until the frame becomes visible, so a panel nobody opens never costs its request.
From the lesson Turbo Drive and Turbo Frames
-
What does a morphing page refresh keep, and what must you add yourself for inline frame updates?
Morphing changes only the nodes that differ, and the turbo-refresh-scroll setting preserve keeps the scroll position. A frame swap announces nothing and moves focus only to an autofocus element, so inline updates need focus handling and a polite live region.
From the lesson Turbo Drive and Turbo Frames
-
What does a turbo-stream element carry, and which actions can it name?
An action and a target. The eight actions are append, prepend, replace, update, remove, before, after and refresh; replace and update also accept method="morph".
From the lesson Turbo Streams and model broadcasts
-
How can one form submission update a list, a counter and the form at the same time?
Answer with several stream elements in one response, each with its own target, built from the partials the page first rendered. No custom JavaScript is needed.
From the lesson Turbo Streams and model broadcasts
-
Why keep a format.html branch beside format.turbo_stream?
Turbo asks for a stream only on non-GET form submissions. Links, GET requests and clients without Turbo never send that Accept type, so they still need the ordinary redirect with status 303.
From the lesson Turbo Streams and model broadcasts
-
How does a saved record update every browser showing it, with no controller code?
broadcasts_to on the model and turbo_stream_from in the view. After the commit, a background job sends the stream over Action Cable to every subscriber; broadcasts_refreshes_to sends a single debounced page refresh instead.
From the lesson Turbo Streams and model broadcasts
-
A stream name is signed. Does that keep visitors away from data they may not see?
No. Signing stops a forged name, but a valid one is handed to anyone the page is rendered for. Decide who may subscribe by gating that render, or with subscription_allowed? on a custom channel.
From the lesson Turbo Streams and model broadcasts
-
How do you test stream responses and broadcasts without a browser?
assert_turbo_stream checks a stream response in an integration test, and Turbo::Broadcastable::TestHelper captures broadcasts once the queued job is performed.
From the lesson Turbo Streams and model broadcasts
-
How does Stimulus attach a controller to the page?
It connects the JavaScript class to every element whose data-controller attribute names that controller's identifier.
From the lesson Stimulus controllers
-
What do actions, targets and values give a Stimulus controller?
Actions wire DOM events to its methods, targets name the elements it works on, and values carry typed data from data attributes. The HTML declares what matters and the JavaScript does the work.
From the lesson Stimulus controllers
-
What are Stimulus classes and outlets for?
Classes let a controller read CSS class names from its HTML instead of hard-coding them; outlets let it reach other controllers on the page.
From the lesson Stimulus controllers
-
Why must disconnect() take down what connect() set up outside the element?
Every Turbo swap runs disconnect() on the old controller and connect() on the new one. A listener that connect added to the window or the document, and nothing removed, multiplies with each visit.
From the lesson Stimulus controllers
-
What does progressive enhancement ask of a page that uses Stimulus?
The page works as the server sends it, and JavaScript only improves it. Interactive widgets also need keyboard support, ARIA state and live regions.
From the lesson Stimulus controllers
-
When do you reach for Stimulus rather than Turbo alone?
When the state exists only in the browser, such as a total that updates while a quantity is typed. State the server holds travels with Turbo.
From the lesson Stimulus controllers
-
What does Action Cable add to an app, and when is a custom channel worth writing?
Long-lived WebSocket connections, so the server can push messages at any moment. Write a channel of your own when the data is not a model change, the payload is not HTML, or the client must send messages back; otherwise Turbo Streams broadcasts already cover it.
From the lesson Action Cable and Solid Cable
-
How does ApplicationCable::Connection decide who is on the other end?
It identifies the user from the signed session cookie. When it cannot, reject_unauthorized_connection closes the socket before any channel runs.
From the lesson Action Cable and Solid Cable
-
What do stream_for and broadcast_to do in a channel?
stream_for model subscribes the client to a stream named from the model's GlobalID, and broadcast_to model, data sends that data to every subscriber of the stream. A channel calls reject for a subscription it refuses.
From the lesson Action Cable and Solid Cable
-
How does Solid Cable deliver messages, and what does the Redis adapter change?
It writes each message to a table that every app process polls every 0.1 seconds, and trims rows after a day. The Redis adapter takes that load off the database and pushes messages with no polling delay.
From the lesson Action Cable and Solid Cable
-
How are Action Cable connections and channels tested without a browser?
With ActionCable::Connection::TestCase and ActionCable::Channel::TestCase: subscribe triggers subscribed, perform calls an action, and assertions check the streams and the broadcasts.
From the lesson Action Cable and Solid Cable
-
Which PWA files does a new Rails 8.1 app generate, and are they switched on?
app/views/pwa/manifest.json.erb and service-worker.js, as apps have had since Rails 7.2, but their two routes and the layout's manifest link stay commented out.
From the lesson PWA files and Hotwire Native
-
How do you switch the PWA scaffold on, and how do you check it?
Uncomment the two routes, and turn the layout's manifest link from an ERB comment into output. /manifest.json should then answer 200 application/json, and the service worker 200 text/javascript.
From the lesson PWA files and Hotwire Native
-
What does Hotwire Native do with the pages of your Rails app?
It shows the HTML your server sends inside a web view of a native app, and turns link taps into native navigation, so a new screen is a new Rails page that reaches users without a new app release.
From the lesson PWA files and Hotwire Native
-
When does a Hotwire Native screen need a bridge component, and when a fully native screen?
A bridge component when a web screen needs one native control; a fully native screen only where fidelity or a platform API demands it. Give each native screen a URL so the same navigation reaches it.
From the lesson PWA files and Hotwire Native
-
In a path configuration, why does the catch-all rule go first?
Rules match a URL's path with regex patterns and are applied in order, later matches overriding earlier ones. Bundling the file and also serving it lets you change navigation without a new build.
From the lesson PWA files and Hotwire Native
-
Why can allow_browser versions: :modern break a Hotwire Native app?
It can refuse the shell's own web view, so the app's screens would show the refusal page instead of your HTML.
From the lesson PWA files and Hotwire Native
-
What does bin/rails generate authentication add to an app?
Two models, User and Session; a Current class for per-request state; an Authentication concern; two controllers; a mailer; two migrations; and the bcrypt gem. All of it is ordinary code inside your app, yours to read and change.
From the lesson The Rails 8 authentication generator
-
Why does the generated sign-in call User.authenticate_by rather than find_by followed by authenticate?
authenticate_by digests the password whether or not the email matches a row, so an unknown address takes about as long as a wrong password and the timing reveals no accounts. The sign-in is also rate-limited to 10 attempts in 3 minutes.
From the lesson The Rails 8 authentication generator
-
How long does the generated password reset link work, and what ends it early?
Fifteen minutes, through the reset token of has_secure_password. A password change kills it, a completed reset signs the account out of every browser, and the reset form answers the same way for any email.
From the lesson The Rails 8 authentication generator
-
What does the authentication generator leave for you to build?
Sign-up, email confirmation, account lockout, a list of active sessions and multi-factor sign-in. It secures users who already exist but never creates them.
From the lesson The Rails 8 authentication generator
-
After you generate authentication, why do a new scaffold's tests fail, and what is the right fix?
Its controllers now require a sign-in, and a fresh app has no root_url. Add a root route and sign in through a helper such as sign_in_as in the test setup, rather than removing the guard.
From the lesson The Rails 8 authentication generator
-
Sign-up takes three posts. Which one is new work, and what must it have?
The registration. It needs allow_unauthenticated_access, since nobody has a session yet, and a rate limit, because it writes rows and sends mail for anyone who asks.
From the lesson Sign-up, email verification and settings
-
Why does a verification link made with generates_token_for need no database column?
The token carries the record id, the block's value and the expiry as signed JSON that can be read but not forged. It stops working once the signature, the time window or the block's value no longer matches.
From the lesson Sign-up, email verification and settings
-
How do you change a user's sign-in address without locking them out?
Store the new address in unconfirmed_email and keep signing in with the old one. Swap the columns only when a link sent to the new address comes back; minting that link from the claim makes a newer claim kill the older link.
From the lesson Sign-up, email verification and settings
-
How does password_challenge make a password change ask for the current password, and what is the trap?
It checks the given value against the stored digest, but only when the attribute is present, so strong parameters must give it a default. The change should also end the user's other sessions.
From the lesson Sign-up, email verification and settings
-
How should an account export or deletion be carried out?
The request only enqueues it, and a job that is safe to run twice does the work. A deletion decides which rows stay for the accounts team and what is removed from them.
From the lesson Sign-up, email verification and settings
-
How is a TOTP code computed?
The user's authenticator app and the server each hold a copy of one secret and combine it with the current time, so a new six-digit code appears every 30 seconds.
From the lesson MFA, passkeys and social login
-
How should an app keep a TOTP secret and its recovery codes?
Store the TOTP secret encrypted at rest and never log it, since anyone holding it can generate valid codes. Hash the recovery codes and let each one work only once.
From the lesson MFA, passkeys and social login
-
How does a passkey sign a user in without any shared secret?
The device keeps the private key and the server stores only the public key. The device signs the server's challenge, which proves it holds the key without ever sending it.
From the lesson MFA, passkeys and social login
-
Why can a spoofed page not obtain a valid passkey signature?
The credential is bound to its relying-party ID, and nothing is signed for a page whose origin does not match that ID.
From the lesson MFA, passkeys and social login
-
How does a Rails app stop login CSRF when a user starts a social sign-in?
OmniAuth 2.x starts the provider login with a POST, and omniauth-rails_csrf_protection checks the Rails authenticity token on that POST.
From the lesson MFA, passkeys and social login
-
When may a provider sign-in be linked to an existing user account?
Only when both the provider and your own app have verified that same email address.
From the lesson MFA, passkeys and social login
-
How do the generator, Devise and Rodauth differ as choices?
The generator gives full control and a small footprint, Devise brings its modules and a well-trodden path, and Rodauth puts security defaults and built-in MFA ahead of ecosystem size.
From the lesson MFA, passkeys and social login
-
What is IDOR, and how does a scoped query prevent it?
An insecure direct object reference: a user changes an id in a URL or form and reaches someone else's record. current_account.batches.find(params[:id]) adds the tenant to the WHERE clause, so a foreign id is simply not found.
From the lesson Authorization, roles and multi-tenancy
-
How is a policy object organised?
A plain Ruby class per resource that answers whether a role may take an action on it, with one method per action and one test per role.
From the lesson Authorization, roles and multi-tenancy
-
Why do roles belong on the membership rather than on the user?
The same person can be an owner in one centre and a teacher in another, so the role describes the link between a user and an account.
From the lesson Authorization, roles and multi-tenancy
-
What do the three multi-tenancy designs trade, and which one should an app start with?
A shared schema, a database per tenant and a schema per tenant trade simplicity against isolation and reporting across tenants. Start with the shared schema unless there is a strong reason for another.
From the lesson Authorization, roles and multi-tenancy
-
Which test shows that a tenant scope is really in place?
A request for another tenant's record that expects a 404.
From the lesson Authorization, roles and multi-tenancy
-
What belongs in the log line of a refused authorization?
The user id and the request id; no personal data in the message.
From the lesson Authorization, roles and multi-tenancy
-
Why give the admin area its own namespace and base controller?
The role check then sits in one place: each new admin controller inherits it, and one request test on the base covers the whole area. A mounted dashboard such as Mission Control joins that boundary only through its own base-controller setting.
From the lesson Admin areas and audit trails
-
How does attr_readonly :admin protect a saved user's admin flag?
save leaves the column as it was, update_attribute and update_columns refuse it, and a new Rails 8.1 app raises at the assignment itself. Strong parameters drop the key too, but only for requests through that one controller.
From the lesson Admin areas and audit trails
-
Which kind of write goes around attr_readonly and every callback?
A relation-level write such as update_all. Keep it out of request code, and write its audit row by hand.
From the lesson Admin areas and audit trails
-
How does an after_commit callback with saved_changes make a sound audit trail?
It writes one row for each record a committed transaction changed and none for a rolled-back one, holding the time, the request id, the entry point, the actor and the diff. A row that must never go missing is written inside the transaction instead.
From the lesson Admin areas and audit trails
-
What should an audit row's diff leave out?
Personal data such as a student's name, removed where the row is written; logs travel, and the record id is enough to find the record again.
From the lesson Admin areas and audit trails
-
When does a hand-built admin fit, and what do the admin and audit gems trade?
A hand-built admin suits a small area with stable resources. Administrate, Avo, ActiveAdmin and Madmin trade a DSL for many generated screens; paper_trail and audited trade a table of their own for a ready-made trail; and Avo's licence can settle the choice by itself.
From the lesson Admin areas and audit trails
-
What does perform_later do, and where does the job then run?
It writes the job to the queue and returns at once. A worker process runs the job later, outside the web request.
-
How does Active Job hand an Active Record object to a job?
As a Global ID, a URI such as gid://app/User/42. When the job runs, the worker loads the record again by its id.
-
Which Active Job adapter does each environment of a Rails 8.1.4 app use?
async in development, test in the test environment and Solid Queue in production, where jobs live in the solid_queue_jobs table.
-
Which processes does Solid Queue run, and what does each do?
A supervisor starts the others and replaces any that die. Workers run ready jobs; a job enqueued with no wait is ready as soon as it is inserted. Dispatchers move delayed jobs on once their time comes, and a scheduler enqueues the recurring tasks.
-
Where is Solid Queue configured, and how are recurring tasks declared?
Workers and dispatchers in config/queue.yml. Recurring tasks go in config/recurring.yml, with a job class or a command and a schedule in plain words, such as every hour.
-
On Rails 8.1.4, what happens by default to a job enqueued inside a transaction that then rolls back?
It is enqueued anyway, because perform_later writes straight away, and it fails looking for a record that was never committed. enqueue_after_transaction_commit = true on the job class holds the enqueue until the commit.
-
Why does no Active Job backend promise that a job runs exactly once?
A job's writes and the queue's note that it finished are separate steps, and a sent email cannot be rolled back. A stop, crash or timeout between them leaves the job looking unfinished, so it runs again.
-
How does a job make a second delivery harmless?
It writes with a unique index on an idempotency key worked out from its arguments, so upsert_all turns the repeat into a no-op in the database instead of a race in Ruby.
-
Why does a long import written as a single perform start over after a deploy?
Solid Queue's supervisor gives workers shutdown_timeout, five seconds by default, to stop. A job still running then is cut off and later runs again from its first line.
-
Which Active Job feature lets a long import pick up where it stopped instead of starting over?
Continuations, which split the job into resumable steps.
-
Why does a mailer method with both a .text.erb and an .html.erb view send a multipart email?
Each view renders one body, so the message carries a text and an HTML alternative and each mail client shows the one it can. The with(...) parameters reach both views.
-
What does deliver_later put on the queue?
An ActionMailer::MailDeliveryJob holding the mailer's name, the method's name and the params. A worker renders the views and delivers; on Rails 8.1 that job uses the default queue.
-
Why should a controller call deliver_later rather than deliver_now?
deliver_now renders the views and talks to the mail server inside the request, so the browser waits on a machine the app does not control. A job also gets retries if delivery fails.
-
How can tests check a mail without any mail server?
The :test delivery method collects every message in ActionMailer::Base.deliveries, which assert_emails and assert_enqueued_email_with read.
-
Where do mailer previews live, and what do they show?
In test/mailers/previews. Each method builds one message, which development shows in the browser without delivering anything.
-
How does an inbound email reach a Rails app?
As an HTTP request to an ingress, sent by the mail server or the mail provider. Action Mailbox stores it as an InboundEmail row, with the raw message in Active Storage, before any mailbox runs.
-
How does Action Mailbox pick the mailbox for a message?
The routes in application_mailbox.rb are tried in order, and the first one whose pattern matches a recipient hands the message to its mailbox.
-
What happens to an InboundEmail once its mailbox has run process?
It ends as delivered, failed or bounced, and is incinerated 30 days later by default. Do the work inside process and treat the row as a log, never as your own data.
-
What does installing Action Mailbox add, and which ingress does it switch on?
application_mailbox.rb, where the routes live, and two migrations. Every ingress stays off until you choose one.
-
Which rows does one Active Storage upload write, and when do the bytes reach the service?
A blob row with the file's metadata and an attachment row that ties the blob to a record. The bytes go to the service after the transaction commits.
-
What decides where Active Storage keeps a file's bytes?
The service named in config/storage.yml: Disk, S3, GCS, or a Mirror that writes to a primary and copies to its mirrors in a background job.
-
How do a redirect URL and a proxy URL serve the same attachment differently?
A redirect URL sends the browser on to a signed service link, so the download stays off the app. A proxy URL streams the bytes through the app, where a CDN can keep them. Neither asks who is fetching, so private files need a controller of your own.
-
Which processor makes image variants in a new Rails 8.1.4 app, and what did the lesson's run use?
A new app uses :vips. The run used :mini_magick, on a machine without libvips, and turned a 400x300 image of 944 bytes into a 128x96 thumbnail of 329 bytes.
-
What does bin/rails action_text:install set up, and where does has_rich_text :body keep the content?
It pins Trix and the Action Text helpers in the import map, adds actiontext.css and copies the Active Storage and Action Text migrations. has_rich_text adds no column: the content goes to the one shared action_text_rich_texts table.
-
Is Action Text content sanitised when it is saved or when it is rendered?
When it is rendered, against a fixed allowlist, so every reader goes through the same check and no view can forget it. The stored row still holds whatever was submitted.
-
What does Action Text's allowlist keep, and what does it remove?
It keeps headings, bold text and https links, and removes a script element, a javascript: link and inline style and event attributes.
-
What is the safe way to print a rich-text field in a view?
Render the field itself, such as announcement.body. Printing its raw markup with raw or html_safe skips the allowlist and ships whatever the form sent.
-
How do you run a single test file, or a single test, in a Rails app?
Give bin/rails test the file's path, or the path followed by a colon and a line number. With no arguments it runs every test except the system tests; the test folder mirrors app.
From the lesson Model tests, fixtures and Minitest
-
What makes a model test honest about what the database kept?
An assertion that reads the database: assert_difference on a row count, or assert_changes on an attribute read through reload. A refused save then fails the test instead of passing it.
From the lesson Model tests, fixtures and Minitest
-
How do fixture rows refer to each other, and why not by id?
By label. Rails derives every row's id from its label, so associations are written as labels too. ERB in a fixture is for the rare value that has to be computed, such as a password digest.
From the lesson Model tests, fixtures and Minitest
-
What does wrapping each test in a rolled-back transaction give a suite, and what changes when you switch it off?
A clean database for every test without emptying and refilling the tables, so no test sees another's rows and the order stops mattering. after_commit still fires inside it. With use_transactional_tests = false, cleaning up becomes your job.
From the lesson Model tests, fixtures and Minitest
-
How does a test fix the clock, and why should app code read Date.current rather than Date.today?
travel_to, travel and freeze_time move or hold the clock for one test and are undone when it ends. Date.current follows config.time_zone, while Date.today reads the server's own zone: on a server kept on UTC it is still yesterday for users in Asia/Kolkata until 05:30 their time.
From the lesson Model tests, fixtures and Minitest
-
When does a Rails 8.1 suite stay in one process, and what does the seed step of config/ci.rb catch?
A suite of fewer than 50 tests runs in one process. The seed step fails the run when db/seeds.rb has fallen behind the models.
From the lesson Model tests, fixtures and Minitest
-
What does an ActionDispatch::IntegrationTest run for one request?
The whole path from URL to response: the router, the middleware and every filter around the action.
From the lesson Integration tests for controllers and APIs
-
How does an integration test check the page a user lands on after a redirect?
follow_redirect! loads the page the 302 points at, and assert_select reads that page by CSS selector.
From the lesson Integration tests for controllers and APIs
-
In an integration test, what does a request that calls deliver_later leave behind?
A job in the test queue, so the test can count what was queued and run the job only when it wants the mail.
From the lesson Integration tests for controllers and APIs
-
What is the cheapest test level that sees a route, a filter, a status and a redirect?
An integration test.
From the lesson Integration tests for controllers and APIs
-
How does an integration test differ from a controller test?
An integration test calls get or post on a URL, so the router, the middleware and every filter run before the action. A controller test invokes the action directly and skips the router; since Rails 5 the generators write integration tests instead.
From the lesson Integration tests for controllers and APIs
-
What can a system test check that an integration test cannot?
What only a running page shows, such as a Turbo frame swapping a row or a Stimulus controller reacting to a click. It drives the app through a Capybara driver and reads the page that comes back.
-
Does a new Rails 8.1.4 app come with system tests?
Capybara is already in its Gemfile, but there are none until bin/rails generate system_test writes the test case and a first test.
-
What did the lesson's rack_test run of a system test need?
No browser and no server. It ran as a plain Ruby call and printed 1 runs, 4 assertions, 0 failures.
-
Under a browser driver, how long do assert_text and assert_selector keep checking, and under rack_test?
Under a browser driver they retry until the text or element turns up, giving up after Capybara.default_max_wait_time, which is 2 seconds unless you change it. Under rack_test they look once.
-
When is rack_test the right driver for a system test, and when Selenium or Cuprite?
rack_test for a page that works without JavaScript; Selenium or Cuprite when scripts drive the flow. Under rack_test a system test adds little over an integration test.
-
What does rspec:install write, and what does each Rails spec load first?
A .rspec file, spec/spec_helper.rb and spec/rails_helper.rb. Every Rails spec requires rails_helper, which boots the app; an app keeps a single test framework.
-
How do a model spec and a request spec divide the work?
A model spec checks a rule on a model, and a request spec checks what an endpoint answers. Test each rule at the lowest layer that can see it.
-
How do build and create differ in factory_bot?
create saves the record together with the associations it needs, so create(:enrolment) writes three rows. build returns the object unsaved, and since factory_bot 5 its associations are built too, so nothing is written.
-
When do fixtures fit a suite, and when factories?
Fixtures for reference data that every test reads; factories for the records one spec is about. Many suites use both.
-
What is config/ci.rb, and how does bin/ci use it?
It is the whole CI script: named steps, each one a shell command. bin/ci runs them in order and exits non-zero if any step failed.
From the lesson Local CI, linting and security scans
-
Why do the style and security steps of bin/ci run before the tests?
They are fast and fail for cheap reasons, so a missing space or a flagged gem shows up in seconds instead of after a slow suite. A failing step does not stop the run.
From the lesson Local CI, linting and security scans
-
Which RuboCop rules does a new Rails app inherit, and what does bin/rubocop -a do?
The rubocop-rails-omakase rules, which .rubocop.yml inherits so a team need not argue each one. bin/rubocop -a corrects the offences it can, such as a missing space after a comma; rules about logic or naming still need a person.
From the lesson Local CI, linting and security scans
-
What does each kind of check in bin/ci fail to see?
RuboCop reads your code's style and misses a vulnerable dependency; the tests check your code's behaviour and miss a flawed dependency too; the audits read dependency versions and miss a logic bug in your own code.
From the lesson Local CI, linting and security scans
-
Why is a green bin/ci on a laptop not enough?
It runs only when someone runs it, so it proves nothing about the next branch or machine. The generated GitHub Actions workflow runs the same checks on every push, and config/ci.rb takes a check of your own as one more step.
From the lesson Local CI, linting and security scans
-
What does rails new --api leave out of an app?
What only a browser uses: nine middleware layers, among them the cookie jar, the cookie session, the flash, the CSP header, method override and the asset server, so a development request goes through 19 layers instead of 28. ApplicationController inherits from ActionController::API, and no assets, helpers or page layout are generated.
From the lesson API-only Rails and JSON rendering
-
How do you put one browser piece, such as cookies, back into an API-only app?
In two halves: the middleware goes back in config/application.rb, and the matching module is included in the one controller that needs it.
From the lesson API-only Rails and JSON rendering
-
When does each JSON rendering choice fit: as_json with only:, a serializer class or a Jbuilder view?
as_json with only: for a few fields of one row; a serializer class to keep one shape across many endpoints; a Jbuilder view for nested bodies that call URL helpers, such as a self link.
From the lesson API-only Rails and JSON rendering
-
What shape do problem details give an API's errors?
One JSON shape for every error, from RFC 9457, sent as application/problem+json. A validation failure is a 422 whose errors member comes from errors.details, and a problem of type about:blank uses the status phrase as its title.
From the lesson API-only Rails and JSON rendering
-
Why does a keyset page stay correct while rows are deleted, where an offset page does not?
The cursor holds the sort key of the last row sent, so the next query starts its index search right after that row. Deleting a row shifts nothing, whereas an offset counts rows again and skips one.
From the lesson API-only Rails and JSON rendering
-
Why put the version in the URL, and when does an OpenAPI file stay true?
A path prefix such as /api/v1 is visible everywhere and cheap to keep. An OpenAPI file stays true only when the tests generate it or check the app against it.
From the lesson API-only Rails and JSON rendering
-
What does a CORS policy control, and what does it not stop?
Which origins' scripts a browser lets read the API's answers. A client that is not a browser still gets the body: CORS never decides who may call the API, so authentication is still needed.
From the lesson API authentication, CORS and rate limits
-
Why must a CORS policy name each origin instead of allowing whatever origin asks?
An origin check that accepts everything allows every site while looking like a policy. With credentials on and cookies sent cross-site, any site's script could read what the signed-in user can see. Turn credentials on only for an endpoint that really uses cookies, and give it CSRF protection back.
From the lesson API authentication, CORS and rate limits
-
Which request gets a CORS preflight, and how did an unknown origin's preflight come back?
A cross-origin request with an Authorization header is preceded by an OPTIONS request naming the method and headers the script wants. The unknown origin got 200 with no CORS headers, so the browser went no further.
From the lesson API authentication, CORS and rate limits
-
How does an API answer a request with no bearer token, and one with a made-up token?
Both get 401. Without a token the answer is a bare challenge naming the realm; once a client has sent a token, the challenge adds error="invalid_token", as RFC 6750 asks. ActionController::API leaves out the token helpers, so the API's concern includes them.
From the lesson API authentication, CORS and rate limits
-
What does the token table store for each client, and what do scopes and revocation do?
Only a SHA-256 digest of each token, never the token itself. A token without the scope an action needs gets 403, and a revoked token fails on its next request.
From the lesson API authentication, CORS and rate limits
-
Why does the payments endpoint count its rate limit per token instead of per IP address, and what does a refused call get?
Many guardians share one school network, so one address can hold many honest clients. The call over the limit gets 429 Too Many Requests before the action runs, so it never reaches the database; the response may carry Retry-After.
From the lesson API authentication, CORS and rate limits
-
Why must a webhook signature be checked over request.raw_post rather than the parsed JSON?
The sender signed the exact bytes it sent. Parsing first can reorder keys or change whitespace, and the recomputed HMAC no longer matches.
-
Why does the signed string include the timestamp, and how is the signature compared?
A replay with a new timestamp then fails the check. ActiveSupport::SecurityUtils.secure_compare looks at every byte whether or not the signatures match, so the response time reveals nothing about where they differ.
-
How does a webhook receiver treat a replay, and how a duplicate delivery?
A replay resends an old captured request, so the receiver refuses any timestamp outside a five-minute window. A duplicate is the sender retrying with a fresh timestamp and a valid signature, so it is caught on the event id instead.
-
How does insert_all with unique_by tell a first delivery from a retry?
The unique index on event_id skips a repeated row, so the returning array comes back empty and the controller enqueues no second job. A plain upsert writes either way and cannot tell them apart.
-
Why does a webhook receiver answer 2xx before doing the work?
The sender waits only a few seconds, and a slow answer looks like a failure it will retry. Answer as soon as the row is stored and let a background job do the rest under the app's own retry policy.
-
What three habits make an outbound call to a URL a user supplied safe?
An open and read timeout of a few seconds; resolving the host and refusing it when the address falls in a blocked range, before any socket opens; and not following redirects, since a redirected location skips that check.
-
What does Rails answer to a POST that arrives without the authenticity token?
422. The form's own token, or the same value in the X-CSRF-Token header, is accepted, and the sign-in form gets the same check.
From the lesson Rails security defaults: CSRF, XSS and SQLi
-
Why can a CSRF test go green while proving nothing?
The test environment switches forgery protection off by default, so a test of the token check has to switch it on first.
From the lesson Rails security defaults: CSRF, XSS and SQLi
-
How do CSRF and XSS differ, and which one does the authenticity token stop?
CSRF makes a signed-in user's browser send a request your site trusts because the cookie came along; XSS makes your own page run a stranger's script. The token stops CSRF only: a form on another site cannot read it, but a script running inside your page can.
From the lesson Rails security defaults: CSRF, XSS and SQLi
-
Besides raw and html_safe, which ways of printing in a Rails view let a value act as markup?
The <%== %> tag, render inline:, a link whose address is a javascript: URL, and raw JSON written into a script element.
From the lesson Rails security defaults: CSRF, XSS and SQLi
-
Which query forms bind a value safely, and why does a sort key need an allowlist?
Placeholders and hash conditions bind the value; interpolating it into the SQL string does not. A sort key from the request needs an allowlist, since Rails accepted an expression such as length(title) as the order.
From the lesson Rails security defaults: CSRF, XSS and SQLi
-
What should a params.expect list hold for a student editing their own profile?
Only the fields this actor may change in this action, so attributes such as role and centre_id stay out of it.
From the lesson Rails security defaults: CSRF, XSS and SQLi
-
What does Brakeman report for a weakness it finds, and what can it not see?
A warning type, a confidence, a file and a line. A bug in your business rules shows up only in your own tests.
From the lesson Rails security defaults: CSRF, XSS and SQLi
-
Which two files make up Rails credentials, and which of them goes into git?
The encrypted config/credentials.yml.enc goes into git; the key file that decrypts it is git-ignored. Neither is any use without the other, and a server normally gets the key from an environment variable instead of the file.
From the lesson Credentials, secrets and Active Record encryption
-
What changes once config/credentials/production.yml.enc exists, and how does a deploy script get a single value?
Production reads that file, with its own key, in place of the shared one. bin/rails credentials:fetch with the value's name prints just that value, so the script never opens the whole file.
From the lesson Credentials, secrets and Active Record encryption
-
The credentials key file has landed in a commit. What do you do?
Rotate every secret the credentials held and the key itself, then remove the file in a new commit. Rewriting history does not withdraw copies that have already left the server.
From the lesson Credentials, secrets and Active Record encryption
-
Why does changing secret_key_base sign every user out?
The app derives a key from it for each use, with ActiveSupport::KeyGenerator and a salt per use: signed cookies, encrypted cookies such as the session, and each named message verifier. Unless the old value stays registered as a rotation, everything signed or encrypted with it stops reading.
From the lesson Credentials, secrets and Active Record encryption
-
The log shows password as [FILTERED] but a notes field holding a password in plain text. Why?
filter_parameters matches key names, as substrings, and never looks at values. notes matches no entry on the list, so its whole value reaches the log.
From the lesson Credentials, secrets and Active Record encryption
-
What two shapes can an Active Record encrypted column take?
A deterministic column stores the same ciphertext for the same value, so find_by still finds a row by it. A non-deterministic column, the default, stores a new ciphertext on every write.
From the lesson Credentials, secrets and Active Record encryption
-
Which security headers does a default Rails 8.1.4 production app send, and which are missing?
X-Frame-Options SAMEORIGIN, X-Content-Type-Options nosniff, Referrer-Policy strict-origin-when-cross-origin, X-XSS-Protection 0 and X-Permitted-Cross-Domain-Policies none. There is no Content-Security-Policy and no Strict-Transport-Security header, and force_ssl is a comment.
From the lesson HTTPS, security headers, CSP and host checks
-
What does X-Frame-Options SAMEORIGIN do, and what does OWASP prefer where no page needs framing?
It lets only your own pages frame the page, which limits clickjacking. Where nothing needs framing, OWASP prefers DENY or a CSP frame-ancestors rule.
From the lesson HTTPS, security headers, CSP and host checks
-
Behind a proxy that ends TLS, what do config.assume_ssl and config.force_ssl each do?
assume_ssl tells the app every request came over HTTPS, because the proxy is the only way in. force_ssl makes the app insist: it redirects http requests, adds Strict-Transport-Security and marks cookies Secure.
From the lesson HTTPS, security headers, CSP and host checks
-
What goes wrong with force_ssl alone behind a proxy that sends no X-Forwarded-Proto header?
The app sees every request as plain HTTP and redirects it, so visitors loop, and a load balancer asking for /up gets 301 instead of 200. assume_ssl ends both; without it, the health check needs its own exclusion in ssl_options.
From the lesson HTTPS, security headers, CSP and host checks
-
What Strict-Transport-Security value does force_ssl send, and when does a browser take notice of it?
max-age of two years with includeSubDomains. A browser acts on the header only on a response it reached over HTTPS; RFC 6797 tells it to ignore one received over plain HTTP.
From the lesson HTTPS, security headers, CSP and host checks
-
Which two protections does a new app leave switched off, and how do you confirm each one works?
A Content Security Policy, whose initializer ships fully commented out, and host authorization, whose config.hosts lines are comments too. Each is proved by sending a request, never by reading the settings file; the host check runs before the router.
From the lesson HTTPS, security headers, CSP and host checks
-
Why does a weakness check assert the safe behaviour instead of reproducing the weakness?
It has to outlive the fix. A check that expects another account's batch to answer 404 is red on the weak code, green after the fix and red again if the fix is ever undone; one that expected 200 would be deleted the day the weakness went.
-
In what order does the lab work through a weakness?
Read the file, write the check that says what safe means, watch it go red, fix the code, watch it go green.
-
In the lab's batches controller, what makes another account's batch answer 404?
Starting the lookup from the signed-in account, so a record of another account is simply not found and Rails answers 404.
-
The weak memberships update permits role beside email. What can a member do with it?
Make themselves an owner while editing their own address. That is mass assignment, filed under A08 Software or Data Integrity Failures.
-
How did the lab's weak payment controller open a redirect to any site?
Rails refuses to redirect a browser to another host, and the weak code switched that check off with allow_other_host: true.
-
What does a static scanner find, and what does only a reader and a test find?
A scanner finds shapes: a value interpolated into a query, html_safe on a value, a command built from a string. It cannot know which coaching centre a batch belongs to, so missing scopes and tenancy rules need a person and a test.
-
A page loops over nine batches and prints each batch's teacher. How many queries does it send, and how many with eager loading?
Ten: one for the batches and one more per batch for its teacher. includes, preload or eager_load bring that down to two queries, or one.
From the lesson N+1 queries, eager loading and strict loading
-
How does includes decide between two SELECTs and one join?
It sends the preload shape, a second SELECT, unless the chain refers to the association's columns; then it sends one LEFT OUTER JOIN, the eager_load shape. references(:assoc) is the hint when a SQL fragment hides that reference.
From the lesson N+1 queries, eager loading and strict loading
-
Why can preload not filter parents by a child's column, while eager_load can?
preload reads the children in a separate SELECT, so the first query has no child columns to test. eager_load joins them in, so it can filter and sort on them, and such a condition also trims the children each parent comes back with.
From the lesson N+1 queries, eager loading and strict loading
-
What does strict_loading do, and what does the n_plus_one_only mode still allow?
It raises ActiveRecord::StrictLoadingViolationError on any lazy load, so a forgotten eager load fails in tests instead of slowing a page. In n_plus_one_only mode the record itself may still load lazily, but the records its has_many returns are marked strict, so the next step, one query per child, raises.
From the lesson N+1 queries, eager loading and strict loading
-
How can a test fail the day a page starts sending more queries?
Wrap the request in ActiveSupport::Notifications.subscribed on sql.active_record, count the SELECTs, and assert at most the number the page should need.
From the lesson N+1 queries, eager loading and strict loading
-
When does load_async help a page, and why does it not cure an N+1?
It runs independent SELECTs side by side, which helps a dashboard that reads two unrelated lists. An N+1 sends its queries one at a time from inside a loop, so there is nothing for load_async to run side by side.
From the lesson N+1 queries, eager loading and strict loading
-
How does an N+1 look in the development log?
A run of identical SELECTs with a different bound value each, one per row of the list, right after the single query that read the list.
From the lesson N+1 queries, eager loading and strict loading
-
What does wrapping several writes in Batch.transaction ensure?
They become permanent together or not at all: the block sends BEGIN and COMMIT, and any exception leaving it sends ROLLBACK and keeps rising to the caller.
-
How does raise ActiveRecord::Rollback differ from raising any other exception inside a transaction?
Both roll the transaction back, but transaction swallows ActiveRecord::Rollback, so the next Ruby line after the block still runs. Any other exception reaches the caller.
-
An inner transaction block raises ActiveRecord::Rollback. When is only the inner work undone?
Only when the inner call is given requires_new: true, which makes it a savepoint. A plain nested call joins its parent, so the rollback has nothing of its own to undo and the parent commits the row anyway.
-
In nested transaction blocks, when does after_commit fire?
After the outermost COMMIT, never when an inner block ends.
-
Two admins save the same batch from forms opened earlier. How does a lock_version column protect the first save?
Every update increments lock_version and checks the old value in its WHERE clause, so the second, stale save matches no row and raises ActiveRecord::StaleObjectError instead of overwriting. For a form left open for minutes, keep lock_version in a hidden field.
-
Which Rails tool fits each way concurrent writes go wrong?
A transaction keeps several writes together, a savepoint undoes part of one, lock_version catches a stale save, and row locks make other writers wait for the row.
-
What do create_enum and t.enum give a PostgreSQL table, and how does such a column sort?
A PostgreSQL type whose only values are the labels you list, so the column stores words and the database itself refuses any other label, even from a script that never loads the model. It sorts in the order the labels were declared, not alphabetically.
-
How do Ruby and SQL read a jsonb column?
Active Record returns it as a Hash. In SQL, the ->> operator reads one key as text.
-
What does t.virtual create, and what changed with PostgreSQL 18?
A generated column that the database computes and nobody may write directly. With stored: true it is computed when the row is written; PostgreSQL 18 made the virtual kind, computed when read, the default. On PostgreSQL 17 and earlier, Rails 8.1.4 raises an ArgumentError for t.virtual without stored: true.
-
How does an exclusion constraint stop two overlapping bookings of the same room?
PostgreSQL compares each new row with the saved ones using the operators it names, here room_id WITH = and when_range WITH &&, and refuses the row when every comparison is true. A GiST index answers on each insert, with btree_gist for the plain integer.
-
Which exception does Rails raise when an exclusion constraint refuses a row, and what should the app do?
ActiveRecord::ExclusionViolation, a subclass of StatementInvalid, for PostgreSQL error 23P01. Rescue it where the booking is created and show the form again.
-
Why can a 10:00 to 11:00 slot and an 11:00 to 12:00 slot both be saved under the constraint?
A Ruby range written with three dots leaves its end out, so PostgreSQL stores 10:00 up to but not including 11:00, and ranges that only touch share no instant. A two-dot range keeps its end and is refused.
-
Which databases does a new Rails 8.1 app use in production?
Four: the primary, plus cache for Solid Cache, queue for Solid Queue and cable for Solid Cable. Development and test have one database each.
-
Where do the migrations and the schema of the cache database live, and which database is seeded?
In its own migrations folder, named by the migrations_paths key, and in db/cache_schema.rb, never in db/schema.rb. Only the primary is seeded; generate a migration for another database with --database cache, and migrate it with db:migrate:cache.
-
Who keeps a replica up to date, and how does database.yml keep Rails' tasks away from it?
The database server copies the primary; Rails copies nothing. The replica's entry names the same database with a user that may only read, and replica: true keeps tasks such as migrations off it.
-
How do connects_to and connected_to send reads to a replica?
connects_to in ApplicationRecord maps the writing role to the primary and the reading role to the replica, and connected_to(role: :reading) uses the replica for one block. Outside any block the role is writing, so nothing reads the replica unless code asks.
-
What two surprises can code meet inside connected_to(role: :reading)?
Rows that are a little behind the primary, because the replica lags; and ActiveRecord::ReadOnlyError for any write, raised before it reaches the database.
-
What does Rails' database selector do with each request?
It sends GET and HEAD requests to the replica, unless the visitor wrote something in the last 2 seconds.
-
Why can a column rename on a live app not be one migration?
Old code keeps serving requests during the deploy: the old column must stay until no instance reads it, and NOT NULL must wait until every row has a value.
-
In what order do the steps of an expand-and-contract rename ship?
Migration 1 adds the new column as nullable; deploy A writes both columns; migration 2 fills the old rows; migration 3 adds NOT NULL; deploy B reads only the new column and ignores the old one; migration 4 drops the old column.
-
What rule must every migration of an expand-and-contract plan keep?
Add before you remove, and switch readers before you drop: each migration must be safe for the code that shipped before it and for the code that ships after it.
-
What does listing the old column in ignored_columns do in deploy B?
It removes the column from the model's attribute_names at once, so the running code stops reading it before migration 4 drops it.
-
Where should a backfill of a big table run?
In a job that walks the table in batches, outside the migration files: the Rails guide on migrations recommends keeping data changes out of them.
-
When does the generated container entrypoint run db:prepare, and what does that mean for migrations?
Only when the command ends in ./bin/rails server, just before the server starts, so a console or a one-off runner never migrates by accident. Migrations therefore run while old containers still serve traffic, and each must be safe for them.
-
What goes into a fragment cache key, and where does the record's version go?
The key names the template path, a digest of the template and the record; the record's version is stored with the entry. The key stays the same, so an update rewrites that entry instead of leaving a dead one behind.
From the lesson Caching with Rails and Solid Cache
-
How does touch: true on a belongs_to make Russian-doll caching pay?
Each save of the child also updates the parent's updated_at, so the outer fragment no longer matches and rebuilds. Only the changed inner fragment and its wrapper are rendered again; every unchanged sibling is read from the cache.
From the lesson Caching with Rails and Solid Cache
-
What does cached: true add to render with collection:?
It reads every fragment of the collection in one multi-read, instead of one cache read per row.
From the lesson Caching with Rails and Solid Cache
-
How do you use Rails.cache.fetch without a stampede or a leak of one user's data to another?
Put the user in the key of anything per-user. Set race_condition_ttl so that, when an entry expires, one reader rebuilds it while the others keep reading the old value for a moment.
From the lesson Caching with Rails and Solid Cache
-
Which cache store does each environment of a new app use, and what are Solid Cache's limits?
Solid Cache in production: a database-backed store that drops its oldest entries first, keeps entries two weeks unless max_age says otherwise, and gets a max_size of 256 MB from the generated cache.yml. Development uses memory_store and test uses null_store.
From the lesson Caching with Rails and Solid Cache
-
How do you measure the cache hit ratio, and why size the database for the cold cache?
Count the hit field in the payload of cache_read.active_support events. The misses decide the database load, and after a flush or a deploy every read misses, so the database has to carry the empty cache, not the warm one.
From the lesson Caching with Rails and Solid Cache
-
What does the Completed line at the end of each request in the Rails log tell you?
The total time, the time spent rendering views, the SQL time with its query count and cached queries, and the garbage collector's pauses. Queries run during the render are taken out of Views, so no millisecond is counted twice.
From the lesson Profiling and tuning a Rails app
-
What does the Server-Timing header list in development, and why is it off in production?
One name;dur= entry per Active Support notification name, with the milliseconds of every event of that name added up, so an N+1 shows as one large sql.active_record entry. Production leaves it off because such metrics can expose sensitive details about the app and its infrastructure.
From the lesson Profiling and tuning a Rails app
-
What does a sampling profiler such as Vernier add to the log and the header?
The names of the methods that took the time. It records what each thread is running every few hundred microseconds, 500 by default in Vernier, so the busiest methods rise to the top.
From the lesson Profiling and tuning a Rails app
-
Where does YJIT run in a Rails 8.1 app?
Everywhere except development and test: the generated setting is config.yjit = !Rails.env.local?.
From the lesson Profiling and tuning a Rails app
-
When do more Puma threads help, and when do you need more workers?
Threads share one process and only one runs Ruby at a time, so extra threads help only while requests wait on the database or the network. Workers are forked processes with their own threads, so several of them use several CPU cores.
From the lesson Profiling and tuning a Rails app
-
What happens when the connection pool is smaller than the number of threads, and what does a performance budget do?
Threads beyond the pool's size wait for a connection to come back, and one that waits too long raises ActiveRecord::ConnectionTimeoutError. A performance budget is a test that counts a page's queries or measures its p95 and fails the build when the page gets slower.
From the lesson Profiling and tuning a Rails app
-
Which settings does production.rb change from development?
It eager-loads every class at boot, stops showing local error reports to visitors, logs at info to standard output, and moves the cache and the Active Job queue into the database with Solid Cache and Solid Queue, so a fresh server needs no Redis.
-
Why does a new app leave assume_ssl, force_ssl and config.hosts commented out?
So a first Kamal deploy works before TLS is set up. Turn the SSL pair on once the app serves HTTPS; an app made with --skip-kamal has them on from the start.
-
How does the generated Dockerfile keep the final image small?
It builds in two stages. The build stage installs the gems and precompiles Bootsnap and the assets; the final image copies only the result, runs as a non-root user with UID 1000 and starts the server through Thruster.
-
When does bin/docker-entrypoint run db:prepare, and how can that go wrong?
Only when the command's last two arguments are exactly ./bin/rails and server. A flag added after server makes it skip the migration without a word.
-
How does a generated Rails app keep secrets out of its Docker image?
.dockerignore leaves the credentials key file and the .env files out of the build context, and the key reaches the container as an environment variable when it starts, never as a file copied into a layer.
-
What does the top of a generated config/deploy.yml name?
The service, which is the base name of every container; the image pushed to the registry; the servers, by role; the registry; the env, split into clear values and secret names; aliases for console, shell, logs and dbc; and the volumes that survive each rebuild.
-
Where do the values listed under env.secret in deploy.yml come from?
From .kamal/secrets, so a secret such as the credentials key never lives in a committed file. Variables under env.clear travel into the container unchanged.
-
What does bin/kamal config do, and does it touch a server?
It reads and checks deploy.yml and prints the config as Kamal resolves it: roles, hosts, the primary host, the image names and the version. It runs on your laptop only and does not even open .kamal/secrets, so it is the first thing to run after a change.
-
Which moves make up one bin/kamal deploy, in order?
Build the image on your laptop, push it to the registry, pull it on each server, boot the new container, hand traffic to it through kamal-proxy, and stop the old container.
-
When does kamal-proxy move live traffic to the new container?
Once a GET of /up on the new container returns status 200. Until then the old container keeps answering, and Kamal stops it only after the swap.
-
What version does Kamal give a deploy in a git checkout, and what uses it later?
The HEAD commit, unless VERSION is set. bin/kamal rollback takes such a version to go back to one that ran before.
-
Which settings does Rails give every SQLite connection in production?
Six from the adapter's defaults, among them journal_mode WAL, synchronous NORMAL and foreign keys on, plus a memory map, a journal size limit and a page cache. The adapter applies them to every connection it opens, on all four databases.
-
database.yml sets timeout: 5000, yet the busy_timeout pragma reads 0. Why?
Rails never sets that pragma. It gives the gem a Ruby busy handler that waits the five seconds and releases the interpreter lock between retries; SQLite allows one busy handler per connection, so the pragma keeps its default.
-
Why does a Rails 8 app on SQLite open four database files?
The app's own tables, plus a file each for the cache, the job queue and the cable messages, which the three Solid gems keep in place of Redis on one server. Separate files mean separate write locks, and all four sit on one volume, so one backup covers them.
-
While the app runs, which files make up each SQLite database?
Three: the .sqlite3 file, a -wal file of committed pages not yet folded back in, and a shared -shm file.
-
How do readers and writers share a SQLite database in WAL mode?
Readers never block the writer and the writer never blocks readers, but only one writer runs at a time. A second writer keeps retrying until its busy timeout runs out, then raises SQLite3::BusyException, so short transactions are the whole technique.
-
What do IMMEDIATE transactions change, and when does PostgreSQL fit better?
An IMMEDIATE transaction takes the write lock at BEGIN, so on a busy database it fails at the start rather than halfway through its work. PostgreSQL runs as a server that accepts many writers at once and can be shared by several app servers.
-
How do you pull the lines of one failing request out of a busy production log?
Search for its request id. A new app's production.rb wraps standard output in tagged logging with one tag, the request id, so every line of a request starts with it.
-
Where does the request id come from, and why does that help with a load balancer?
The ActionDispatch::RequestId middleware keeps the X-Request-ID header a client or proxy sent, or makes a UUID, so the Rails log and the load balancer's log share one string.
-
What does Rails.event send to a subscriber?
A hash with the event's name, payload, tags, context, timestamp and source location, to every subscriber, which is a plain object with an emit method. Rails 8.1 added it as ActiveSupport::EventReporter.
-
Is a secret inside an event's payload filtered before subscribers see it?
When the payload is a Hash, yes: the reporter runs the app's filter_parameters list over it, so the value arrives as [FILTERED]. An event object of your own class is not filtered.
-
How do Rails.error.handle, record and report differ?
handle runs a block, reports any exception, swallows it and returns a fallback; record runs a block, reports and raises again; report sends an exception you have already caught. set_context adds values that merge into every later report of the request or job.
-
Why send every error through Rails.error instead of calling an error service directly?
Changing the error service later then means changing one subscriber, not every rescue in the app.
-
How long does a Rails minor series receive fixes?
Bug fixes for one year after its first release and security fixes for two; after that it is at its end of life and no new gem is released. New features land only on the main branch, in the next minor.
-
What happens to the newest Rails series when no new minor ships within a year?
The maintenance policy extends its support until the next minor appears.
-
Why upgrade one Rails minor at a time?
An API deprecated in one minor is usually removed in the next, so a jump over a minor skips the release where the old call still works with a deprecation notice.
-
Why upgrade Ruby and Rails in separate commits?
They fail in different places and need different rollbacks. Kept apart, each failure has one obvious cause and one clean revert.
-
What do identical, create and conflict mean in the output of bin/rails app:update?
identical means the file on disk already matches the new template; create adds a file the old version never generated, such as config/ci.rb; conflict means the template differs from your file, so read the diff before you reply.
-
Which replies does bin/rails app:update accept for a conflict?
y takes the template, n keeps your file, m runs a merge tool and d shows the diff first. Answering a, overwrite all, suits only a fresh copy, never a real app.
-
How are the new framework defaults switched on during an upgrade?
One line at a time in the new framework defaults initializer: uncomment it, ship it, watch it, then take the next.
-
What do the t and l helpers do?
t(key) looks a string up under the current locale, with dotted keys, lazy keys such as t('.title') that read from the view's path, and the plural form the locale's own rule picks. l(value) formats a date or a time from the locale's entries.
-
A before_action sets I18n.locale = :hi. Why can a later request served by that thread start in Hindi?
The i18n gem keeps the locale per fiber, and a Puma thread serves its requests on one fiber. Rails resets Current and returns the database connection after a request, but it never resets I18n.locale.
-
How do you set the locale for one request without leaking it to the next?
In an around_action that calls I18n.with_locale, which saves the old locale and puts it back when the action is done.
-
Which of India's languages does rails-i18n 8.1.0 lack, and what do you do about one?
It ships 123 locales with Hindi and Indian English among them, but Marathi only as mr-IN and no Gujarati at all. Add the missing file under config/locales/, using the gem's Hindi file as the model.
-
How should an app for Indian users store and show times?
Store every instant as UTC and set config.time_zone to Kolkata, which pins Time.zone to Asia/Kolkata. Read the current time with Time.current or Time.zone.now; models hand stored columns back in Time.zone, so readers see IST while the stored row never changes.
-
How do you show a rupee amount with Indian digit grouping in Rails?
Call number_to_currency with a delimiter pattern that groups the digits in twos after the first three from the right. Wrap it in one helper that takes integer paise and reads the current locale, so every page, mailer and receipt formats money the same way.
-
Why keep money as integer paise and format it only at the edge?
Every sum and comparison then stays in whole paise. The helper divides by 100.0 only at the edge, and number_to_currency rounds the result to two places for display.
-
What makes up a Rack 3 response?
A status, a hash of headers whose names are lower case, and a body the server reads with each and must close.
From the lesson Rack middleware, the executor and threads
-
What may a Rack middleware do with the response body?
Set headers and wrap the body, calling each on the original as the server reads it. It may treat the body as a whole only when the body responds to to_ary, because a Rack body can be a stream.
From the lesson Rack middleware, the executor and threads
-
Why does it matter where a middleware sits in the stack?
Its position decides what it sees. Placed below ActionDispatch::RequestId, a timing middleware has the request id, also times the error pages ShowExceptions makes, and runs inside the executor.
From the lesson Rack middleware, the executor and threads
-
How do mount and to: differ when routing to a Rack app, and what do both leave out?
mount hands the app the part of the path below its prefix, while to: hands it the whole path. Neither runs a controller's filters, so a mounted app needs a check of its own, such as a routing constraint.
From the lesson Rack middleware, the executor and threads
-
What does the Rails executor do around each request, job and runner script?
Its run hooks switch the query cache on. Its complete hooks run once the response body is closed: they clear Current, switch the query cache off and give leased database connections back. In development the reloader brings in changed code.
From the lesson Rack middleware, the executor and threads
-
What leaks between requests that three Puma threads serve at the same time?
Anything stored on shared objects: memos and attributes on classes, mutable constants, globals and Thread.current values. Keep per-request data in the env, the controller or Current.
From the lesson Rack middleware, the executor and threads
-
You start a thread of your own inside a Rails app. What must its work run inside?
Rails.application.executor.wrap, so the thread gets the same set-up and clean-up as a request.
From the lesson Rack middleware, the executor and threads
-
What are Active Support's core extensions, and what do they cost?
Methods such as blank?, presence, 2.days and to_sentence that Rails adds to Ruby's own classes when it loads, so code reads almost like English. The cost is that they change classes Ruby ships with.
From the lesson Active Support: extensions and notifications
-
How do nil?, blank? and present? differ?
nil? is plain Ruby and is true only for nil. blank? is true for nil, false, empty strings and arrays, and strings of only whitespace. present? is the opposite of blank?.
From the lesson Active Support: extensions and notifications
-
What does presence return, and what is it good for?
The receiver when it is present, otherwise nil, so name.presence || "N/A" gives a default in one expression.
From the lesson Active Support: extensions and notifications
-
What does ActiveSupport::Notifications.instrument do?
It wraps a block and publishes an event with a name and a payload hash. Every subscriber whose pattern matches the name, as an exact string or a regex, receives an event object with the timing and the payload.
From the lesson Active Support: extensions and notifications
-
How should your own notification events be named, and why?
As action.namespace, such as calculate_total.fees, the same shape Rails uses for process_action.action_controller and sql.active_record, so a regex like one ending in .fees can collect a whole family.
From the lesson Active Support: extensions and notifications
-
A new monitoring subscriber doubled a page's p99 latency. Why, and what is the fix?
Subscribers run inline, on the request's own thread, right after the instrumented block, so a network call inside one adds its time to every request. Hand slow work to a background job and return at once.
From the lesson Active Support: extensions and notifications
-
What does rails plugin new feature_flags --mountable write?
A gemspec, lib/feature_flags/engine.rb, a routes file drawn on the engine rather than on the application, an app/ tree under feature_flags/, and a complete host application in test/dummy for the engine's tests.
From the lesson Engines, generators and application templates
-
What does isolate_namespace move into an engine's own module?
Its models, controllers and helpers, its table names, which gain a prefix such as feature_flags_, and its route helpers. Without it, both apps' FlagsController classes are one constant and their flags tables one table.
From the lesson Engines, generators and application templates
-
How does a --mountable engine differ from a --full one?
A mountable engine gets its own namespace and routes; a full engine shares the host app's.
From the lesson Engines, generators and application templates
-
How do an engine's migrations reach the host app?
bin/rails feature_flags:install:migrations copies them into the host app with new timestamps.
From the lesson Engines, generators and application templates
-
When does a team write a custom generator, and when an application template?
A generator, built on Rails::Generators::NamedBase with .tt templates, for files the team keeps writing by hand. An application template, a script of Thor actions run by rails new -m or bin/rails app:template, sets up each new application the way the team agreed.
From the lesson Engines, generators and application templates
-
When does a slice of code become an engine, a package or a separate app?
An engine when a second application will mount the code; a packwerk package, a folder whose package.yml names what it may reference, when one application needs its dependencies kept honest; a separate application when the slice must be released on its own.
From the lesson Engines, generators and application templates
-
Where should a business rule live: a model method, a service object or a service layer?
Where its data and its transaction are. A model method, perhaps in a concern, while one model owns the use case; a service object when several models or another system share it; a whole service layer only when its many thin forwarding classes buy the team a single entry point.
-
When does a use case move from a model method into a service object?
When no single model owns it: it writes several models as equals, or it coordinates another system such as a payment gateway, so a model method would hide a second owner.
-
What does each of a form object, a query object and a presenter own, and where do they live?
A form object owns typed input, a query object owns one read and a presenter owns display. A domain namespace such as Fees:: keeps them beside their models, in one folder with one table prefix.
-
What may a model do in its callbacks, and how should work that reaches other models or systems happen?
Change its own state, and nothing else. Work that touches another model or another system follows a domain event reported after the commit, so it cannot undo the payment and a test of one model never meets it.
-
How do you shrink a fat controller without breaking it?
Pin its behaviour with integration tests that go through the request first, then move one job out per step and run the same tests after each. In the lesson the action fell from 41 lines to 13 with the same five tests green throughout.
-
When does a separate service pay for its network calls?
Only when a slice needs a different scaling or release path. Boundaries inside one app come first: a namespace, then packwerk packages or engines.
-
Why put the model behind a provider adapter and a service object?
The adapter is the one class that talks to a model, so another hosted or local model means one new backend class. Tests hand the service a fake backend, so they are fast, repeatable and never reach the network.
-
How does an assistant answer appear word by word without a request waiting for the model?
The controller only enqueues a job and answers 202 at once. The job calls the adapter, which yields the answer a few characters at a time, and broadcasts each piece as a Turbo Stream to the page that subscribed with turbo_stream_from.
-
Which two limits keep an assistant from running up time and money?
A rate limit caps how often one user may ask, and a cost cap refuses calls once that user's daily token budget is spent.
-
What does treating the model's text as untrusted input mean in a Rails app?
Escape it in the view, never eval it, let only actions on a fixed allowlist run, and replace emails and phone numbers before any text is sent out. A raw or html_safe on the model's text undoes the escaping.
-
Can prompt injection be prevented completely?
OWASP's GenAI project lists it as the top risk and doubts that any method fully prevents it, so the app limits what the output can do and what leaves the app.
-
What must a change written by a coding agent get through before it is merged?
The same checks as any contributor's change: the ticket's tests written before the work starts, a green bin/ci and a person who reads the whole diff. In the Rails Foundation's Agents on Rails benchmark the best mean task score was 59.2 %, so a change that looks done is often not.
-
In a Rails interview, what decides how an answer is judged?
The question that comes after it. Say that a job sends the receipt, and the next question is what happens when the queue runs that job twice.
-
Which six parts does every entry of the practice bank have, and which do you read before answering?
Before you answer, read the prompt, what it tests and a first step. Leave the likely follow-ups, the model answer and the rubric for each level until afterwards.
-
Which experience levels can a bank question name?
Any of four: fresher; two to five years; five to ten years; more than ten years. Each question belongs to one topic and names the levels it suits.
-
How do answers at different levels differ?
In depth more than in length. A recall answer names the right feature, a working answer explains how it works and what it costs, and a production answer adds how it fails, with a number that shows it.
-
How do you practise one question from the bank?
Pick one at your level and answer it aloud before reading anything. Then compare with the model answer and note each follow-up you could not answer. A weak score brings the question back sooner.
-
Why should an answer name the Rails version it describes?
Behaviour changes between versions. The worked answers were recorded on Rails 8.1.4 and Ruby 4.0.7, so an answer for another version should say which one it means.
-
How does a machine-coding round differ from a whiteboard round?
You build a small feature in a fixed time, usually 60 to 120 minutes, and the round runs your code against tests. The interviewer cares about the code you commit, not a sketch of an algorithm.
-
Why can half a feature with tests beat a whole feature?
Timeboxing is the skill the round tests, and the tests are part of what is marked: a whole feature left untested because time ran out scores below half a feature that has its tests.
-
Which six areas does the mock rubric score?
Working behaviour, tests written, Rails idioms, security, performance and commit hygiene. A missing test costs points even when the code happens to work, and a security gap costs more than a missing feature.
-
How is each mock timed and scored?
By you: read the spec, start a timer, build until time runs out, then run the mock's checks, which are tests, to see what you missed. Mark an area down when its proof is missing, not when the code merely looks wrong.
-
Why spend the first ten minutes of a 90-minute mock on the spec?
A candidate who reads the spec and sketches a timeline often finishes more than one who starts coding at once. Give every item of the spec a slot in the budget.
-
What does the URL shortener mock ask for?
A short, unique code for each long URL, a redirect that counts clicks, creation that is rate-limited, a show endpoint with the click count, and original URLs limited to http and https.
-
Which pressure does each of the four other mocks add?
Appointment slots must never double-book a slot; a live poll updates its counts in every open browser; a token-authenticated API serves paginated JSON behind a bearer token; a CSV import job reports progress and survives a retry.