💎

Top 76 Ruby on Rails Interview Questions & Answers (2026)

76 Questions 41 Beginner 22 Intermediate 13 Advanced

About Ruby on Rails

Top 100 Ruby on Rails interview questions covering MVC, ActiveRecord, routing, associations, caching, testing, and deployment. Companies hiring for Ruby on Rails roles test this knowledge at every stage — from first-round screens that check the basics to final-round conversations about real-world trade-offs.

What to Expect in a Ruby on Rails Interview

Expect a mix of conceptual and practical Ruby on Rails questions: clear definitions and core-concept checks for junior roles, hands-on scenario questions for mid-level roles, and architecture or trade-off discussions for senior roles. Interviewers usually move from foundational topics toward the kind of problems you'd actually face on the job.

How to Use This Guide

Work through the Ruby on Rails questions in order — Beginner, then Intermediate, then Advanced — so each concept builds on the last. Every question has its own page; bookmark the ones that trip you up and revisit them the day before your interview.

Curated by Tech Baithak Editorial Team  ·  Last updated: June 2026

Beginner 41 questions

Core concepts every Ruby on Rails developer must know.

01

What is Ruby on Rails?

Ruby on Rails (or simply Rails) is an open-source web application framework written in the Ruby programming language. It follows the Model-View-Controller (MVC) architectural pattern and is built around two core principles: Convention over Configuration (CoC) — sensible defaults mean you write less code, and Don't Repeat Yourself (DRY) — every piece of knowledge should have a single authoritative representation. Rails emphasizes rapid development and is used to build applications like GitHub, Shopify, Basecamp, and Airbnb.

Open this question on its own page
02

What is the MVC pattern in Rails?

Rails uses the Model-View-Controller (MVC) pattern to separate concerns. The Model (ActiveRecord) handles data, business logic, and database interactions. The View (ActionView) handles presentation — ERB templates that render HTML. The Controller (ActionController) handles incoming HTTP requests, interacts with the model, and renders the appropriate view. A typical request flow: browser sends HTTP request → Router dispatches to a Controller action → Controller queries Model → Controller passes data to View → View renders HTML response.

Open this question on its own page
03

What is Convention over Configuration in Rails?

Convention over Configuration (CoC) means Rails provides intelligent defaults so developers can follow standard conventions and avoid writing boilerplate configuration. For example: a model named User automatically maps to a database table named users, a controller named PostsController has views in app/views/posts/, and a primary key is always id by default. You only need to configure where you deviate from conventions. This dramatically reduces the amount of configuration code and makes Rails codebases predictable and easy to navigate.

Open this question on its own page
04

What is ActiveRecord in Rails?

ActiveRecord is the ORM (Object-Relational Mapping) layer in Rails. It implements the Active Record pattern — each database table is mapped to a Ruby class, and each row becomes an instance of that class. ActiveRecord handles CRUD operations, associations, validations, callbacks, and database migrations without writing raw SQL. For example: User.find(1), User.where(active: true), user.save. It supports multiple databases (MySQL, PostgreSQL, SQLite) and abstracts away database-specific SQL differences.

Open this question on its own page
05

What is a Rails migration?

A migration is a Ruby file that describes a change to the database schema — creating/dropping tables, adding/removing columns, adding indexes. Migrations allow you to evolve your database schema over time in a version-controlled, reversible way. Run rails db:migrate to apply pending migrations and rails db:rollback to revert the last one. Each migration has an up (or change) method and optionally a down method. The schema.rb file is the authoritative snapshot of the current database schema.

Open this question on its own page
06

What are Rails routes?

Rails routes, defined in config/routes.rb, map incoming HTTP requests (verb + URL path) to controller actions. resources :posts creates 7 RESTful routes automatically: index, show, new, create, edit, update, destroy. You can define custom routes with get '/about', to: 'pages#about'. Run rails routes to list all routes. Routes also generate named path helpers like posts_path and post_path(@post), making it easy to generate URLs without hardcoding strings.

Open this question on its own page
07

What are the 7 RESTful actions in Rails?

When you declare resources :posts, Rails generates 7 RESTful routes/actions: index (GET /posts — list all), show (GET /posts/:id — show one), new (GET /posts/new — render form for new), create (POST /posts — save new), edit (GET /posts/:id/edit — render edit form), update (PATCH/PUT /posts/:id — save changes), and destroy (DELETE /posts/:id — delete). These map directly to CRUD operations and form the backbone of RESTful API design in Rails.

Open this question on its own page
08

What is a Rails generator?

Rails generators are command-line tools that scaffold code files automatically, following conventions. Common generators: rails generate model User name:string email:string creates a model and migration; rails generate controller Pages home about creates a controller with actions and views; rails generate scaffold Post title:string body:text generates the full CRUD stack (model, migration, controller, views, routes). Generators save time and ensure consistent file structure. You can also create custom generators.

Open this question on its own page
09

What is a Gemfile and Bundler in Rails?

The Gemfile is a file in the root of a Rails project that declares all Ruby gem dependencies and their version constraints. Bundler is the dependency manager that reads the Gemfile, resolves compatible versions, and installs them. Run bundle install to install gems. Gemfile.lock records the exact resolved versions to ensure all developers and production servers use the same gem versions. Use bundle exec rails ... to run commands in the context of the bundled gems, avoiding version conflicts.

Open this question on its own page
10

What is the Rails directory structure?

Key directories in a Rails app: app/ — application code (models, views, controllers, helpers, mailers, jobs, channels); config/ — routes, database.yml, application.rb, environments; db/ — migrations, schema.rb, seeds.rb; lib/ — custom library code and tasks; public/ — static files served directly; test/ or spec/ — test files; Gemfile — gem dependencies; config/routes.rb — URL routing. Understanding this layout is key because Rails automatically loads files in app/ based on naming conventions.

Open this question on its own page
11

What are ActiveRecord associations?

ActiveRecord associations define relationships between models using macros. belongs_to — a Post belongs_to a User (posts table has user_id FK). has_many — a User has_many Posts. has_one — a User has_one Profile. has_many :through — many-to-many via a join model (User has_many Groups through Memberships). has_and_belongs_to_many (HABTM) — direct many-to-many with a join table but no join model. has_one :through — one-to-one via another model. Associations generate helper methods like user.posts, post.user, user.posts.create(...).

Open this question on its own page
12

What are ActiveRecord validations?

ActiveRecord validations ensure that only valid data is saved to the database. Declared in the model with macros: validates :name, presence: true, validates :email, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }, validates :age, numericality: { greater_than: 0 }. When you call model.save or model.valid?, Rails runs all validations. If any fail, save returns false, and errors are accessible via model.errors.full_messages. Use save! or create! to raise an exception on failure instead.

Open this question on its own page
13

What are ActiveRecord callbacks?

ActiveRecord callbacks are hooks that execute code at specific points in an object's lifecycle. Order for save: before_validationafter_validationbefore_savebefore_create/update → (SQL) → after_create/updateafter_saveafter_commit. Useful callbacks: before_save :downcase_email, after_create :send_welcome_email, before_destroy :cancel_subscriptions. Be careful with callbacks — they can make models hard to test and understand. Consider service objects for complex business logic instead.

Open this question on its own page
14

What is the difference between render and redirect_to in Rails?

render generates an HTTP response by rendering a view template and returning it to the browser in the same request. The URL in the browser does not change. Example: render :new when create fails (re-displays the form with errors). redirect_to sends a 302 HTTP redirect response, causing the browser to make a new GET request to the specified URL. The URL changes. Example: redirect_to @post after successful create. The Post/Redirect/Get (PRG) pattern prevents duplicate form submissions on browser refresh.

Open this question on its own page
15

What is strong parameters in Rails?

Strong parameters (introduced in Rails 4) protect against mass assignment vulnerabilities by requiring explicit whitelisting of permitted attributes. In the controller, you use params.require(:user).permit(:name, :email, :password) before passing parameters to a model. Without strong parameters, an attacker could submit hidden fields (like admin: true) and modify any attribute. Strong parameters raise an ActionController::ForbiddenAttributesError if you try to pass unpermitted params directly to a model method like create or update.

Open this question on its own page
16

What is ERB in Rails?

ERB (Embedded Ruby) is Rails' default templating engine. It lets you embed Ruby code inside HTML files using special tags: <%= expression %> evaluates Ruby and outputs the result (HTML-escaped), <% code %> executes Ruby without output, and <%- -%> suppresses whitespace. View files use the .html.erb extension. ERB is compiled to Ruby at runtime. Alternatives include Haml (indentation-based, concise) and Slim (even more concise). Rails also supports Jbuilder and json for API responses.

Open this question on its own page
17

What is the difference between GET and POST in Rails forms?

In HTML, forms submit data via GET (appends data to URL as query string — visible, bookmarkable, idempotent — used for search forms) or POST (sends data in request body — not visible in URL — used for creating/modifying data). Since HTML only supports GET and POST natively, Rails uses a hidden _method field and the rack-methodoverride middleware to simulate PATCH, PUT, DELETE for RESTful updates and deletes. Rails form helpers (form_with) automatically include CSRF tokens and set the correct HTTP method.

Open this question on its own page
18

What is CSRF protection in Rails?

CSRF (Cross-Site Request Forgery) is an attack where a malicious site tricks a logged-in user's browser into making unwanted requests to your app. Rails protects against this with an authenticity token — a unique, secret, session-specific token embedded in all non-GET forms. When a form is submitted, Rails verifies the token. If it's missing or wrong, the request is rejected. This is enabled by default via protect_from_forgery with: :exception in ApplicationController. Rails' form_with helper automatically includes the CSRF token.

Open this question on its own page
19

What are Rails helpers?

Rails helpers are modules containing methods used to simplify view templates. They are automatically available in corresponding views. Built-in helpers: link_to "Home", root_path generates an anchor tag; image_tag "logo.png" generates an img tag; form_with model: @post generates a form; number_to_currency(100) formats numbers; truncate(text, length: 100) truncates strings. Custom helpers go in app/helpers/ modules. Helpers keep views clean by extracting reusable presentation logic out of templates.

Open this question on its own page
20

What are Rails scopes?

ActiveRecord scopes are named, reusable query fragments defined in a model using the scope macro. Example: scope :published, -> { where(published: true) } and scope :recent, -> { order(created_at: :desc).limit(10) }. Scopes return an ActiveRecord relation, so they can be chained: Post.published.recent. Scopes with parameters: scope :by_author, ->(author) { where(author: author) }. Scopes make query intent explicit and DRY. They are equivalent to defining class methods but with the added guarantee of returning a relation even when the condition is falsy.

Open this question on its own page
21

What is flash in Rails?

The Rails flash is a special part of the session that stores a message only for the next request — it is cleared afterwards. Commonly used to show success or error notices after a redirect. Example: flash[:notice] = "Post created successfully!" before redirect_to @post. In the view: <%= flash[:notice] %>. flash.now is used when rendering (not redirecting) so the message is available for the current request only: flash.now[:alert] = "Invalid credentials". Flash prevents stale messages from persisting across multiple requests.

Open this question on its own page
22

What is session in Rails?

The Rails session is a server-side (or cookie-based) key-value store that persists data across requests for a single user. By default, Rails uses cookie-based sessions — encrypted and signed session data stored in a browser cookie (CookieStore). Set: session[:user_id] = user.id. Read: session[:user_id]. Clear: session.delete(:user_id) or reset_session. Cookie sessions are limited to ~4KB. For larger or more secure sessions, use ActiveRecord::SessionStore or Redis-backed sessions.

Open this question on its own page
23

What is the asset pipeline in Rails?

The asset pipeline (Sprockets in older Rails, now Propshaft/importmap in Rails 7+) manages and optimizes static assets (CSS, JavaScript, images). It: concatenates multiple files into one (reducing HTTP requests), compresses/minifies them (reducing file size), and adds fingerprinting (MD5 hash in filename) for cache busting. Asset paths in helpers (asset_path, image_tag) automatically use the fingerprinted URL. In production, assets are precompiled via rails assets:precompile to static files served directly by the web server.

Open this question on its own page
24

What is database seeding in Rails?

Database seeding populates the database with initial or sample data using the db/seeds.rb file. Run with rails db:seed. Seeds are useful for: creating an admin user, populating lookup tables, and generating demo data for development. Example: User.create!(name: 'Admin', email: 'admin@example.com', password: 'password'). The find_or_create_by method is useful in seeds to avoid duplicates when re-running. For large datasets or organized seeds, use the Seedbank gem or separate seeder files.

Open this question on its own page
25

What are environment files in Rails?

Rails has three default environments: development (local coding — verbose errors, hot reloading, debug logging), test (running tests — isolated database, faster), and production (live server — optimized performance, asset compilation, less verbose logging). Configuration per environment lives in config/environments/development.rb, etc. Sensitive environment-specific values (API keys, database passwords) are stored in .env files (via the dotenv-rails gem) or Rails credentials (config/credentials.yml.enc) and accessed via Rails.application.credentials.secret_key.

Open this question on its own page
26

What is an ActiveRecord query interface?

ActiveRecord provides a chainable query interface that builds SQL lazily. Key methods: User.all, User.find(id), User.find_by(email: 'a@b.com'), User.where(active: true), User.order(:name), User.limit(10).offset(20), User.select(:id, :name), User.joins(:posts), User.includes(:posts), User.count, User.sum(:amount). Queries are not executed until results are needed (lazy loading). to_sql returns the generated SQL string for debugging.

Open this question on its own page
27

What is the difference between find and find_by in Rails?

User.find(id) looks up a record by primary key and raises ActiveRecord::RecordNotFound if not found. This is used when the record must exist — letting the exception propagate results in a 404 response with proper rescue handling. User.find_by(email: 'a@b.com') searches by any attribute and returns nil if not found — useful when absence is a normal case (e.g., checking login credentials). find_by! raises RecordNotFound like find. Choosing between them communicates intent about whether a missing record is expected.

Open this question on its own page
28

What are partials in Rails views?

Partials are reusable view fragments stored in files prefixed with an underscore (e.g., _post.html.erb). Render with <%= render 'post', post: @post %> or the shorthand <%= render @post %> (Rails infers the partial name from the model). <%= render @posts %> iterates and renders the partial for each item. Partials reduce duplication — a _form.html.erb partial can be shared between new and edit views. Local variables passed to partials are scoped to that partial only.

Open this question on its own page
29

What is concerns in Rails?

Concerns are modules in app/models/concerns/ or app/controllers/concerns/ used to extract and share reusable behavior across multiple models or controllers. They use Ruby's module system with ActiveSupport::Concern, which adds DSL for included and class_methods blocks. Example: a Taggable concern could be included in Post and Product models to share tagging logic. Concerns help keep models slim but can sometimes obscure where behavior is defined — use judiciously.

Open this question on its own page
30

What is has_secure_password in Rails?

has_secure_password is an ActiveModel macro that adds password hashing using bcrypt. It adds password and password_confirmation virtual attributes, automatically hashes the password and stores it in a password_digest column, and adds an authenticate(plain_password) method that returns the user (or false) after BCrypt comparison. It validates presence of password on create and length (72 chars max). Requires the bcrypt gem. Use: user.authenticate(params[:password]) in your sessions controller.

Open this question on its own page
31

What are Rails environments and how do you check the current one?

Rails runs in one of its configured environments (development, test, production, or custom ones). Check the current environment with Rails.env, which returns a string. Use predicates: Rails.env.development?, Rails.env.test?, Rails.env.production?. Set the environment via the RAILS_ENV environment variable: RAILS_ENV=production rails server. Environment-specific configuration in config/environments/ controls things like email delivery, caching, asset compilation, and logging verbosity.

Open this question on its own page
32

What is Rails console?

The Rails console (rails console or rails c) provides an interactive Ruby REPL (Read-Eval-Print Loop) with the full Rails application environment loaded. You can query the database (User.all), create records, call model methods, test code snippets, and inspect configuration — all without writing a script file. In production, use rails c --sandbox to prevent any writes from being committed. The console is invaluable for debugging, data inspection, and one-off data fixes.

Open this question on its own page
33

What is the difference between belongs_to and has_one?

Both define a one-to-one relationship, but from different sides. belongs_to declares that the current model holds the foreign key — e.g., Profile belongs_to :user means the profiles table has a user_id column. In Rails 5+, belongs_to requires the associated record to exist by default. has_one declares that the other model holds the foreign key — e.g., User has_one :profile means Rails looks for user_id in the profiles table. The rule of thumb: the model with belongs_to holds the foreign key column.

Open this question on its own page
34

What is ActiveRecord::Base vs ApplicationRecord?

In older Rails, models directly inherited from ActiveRecord::Base. Rails 5 introduced ApplicationRecord, a custom base class that inherits from ActiveRecord::Base, and all models now inherit from ApplicationRecord instead. This provides a single place to add shared model behavior (shared scopes, class methods, included modules) for all models in the app — similar to how ApplicationController works. It follows the Single Table Inheritance principle and makes it easy to patch or extend ActiveRecord behavior app-wide.

Open this question on its own page
35

What is eager loading vs lazy loading in Rails?

Lazy loading loads associated records only when they are accessed, triggering a separate SQL query each time. This causes the N+1 query problem: fetching 100 posts and accessing post.author on each fires 101 queries (1 for posts + 100 for authors). Eager loading with includes pre-loads associations upfront: Post.includes(:author).all generates at most 2 queries regardless of how many posts exist. Use eager_load for a single JOIN query or preload for separate queries. Always eager-load associations used in views to avoid N+1 issues.

Open this question on its own page
36

What are named routes in Rails?

Named routes give a URL pattern a name, generating helper methods for constructing URLs. resources :posts creates posts_path (returns /posts), new_post_path, post_path(@post), and edit_post_path(@post). For custom routes: get '/about', to: 'pages#about', as: 'about' creates about_path. Named routes produce both _path (relative URL) and _url (absolute URL with host) helpers. Using named route helpers instead of hardcoded strings makes code refactoring easier — change the URL in one place and all helpers update automatically.

Open this question on its own page
37

What is the difference between update and update_attribute?

update(hash) updates multiple attributes at once, runs all validations and callbacks, and returns true/false. update_attribute(name, value) updates a single attribute, skips validations but still runs callbacks. update_columns(hash) updates directly in the database, skipping both validations and callbacks (useful for performance-critical updates or updating without triggering side effects). update_column(name, value) is the single-attribute version. Use update for normal business logic and update_columns for low-level or bulk updates where you want maximum performance.

Open this question on its own page
38

What is Rails scaffolding?

Scaffolding (rails generate scaffold ModelName field:type ...) generates a complete CRUD stack in one command: the model, migration, controller with all 7 RESTful actions, views (index, show, new, edit, _form partial), routes (resources :model_names), and tests. It is useful for prototyping and learning Rails conventions, but generated code is often too generic for production — most developers use it as a starting point and customize from there. For APIs, rails generate scaffold --api generates controllers without views.

Open this question on its own page
39

What are Rails layouts?

Layouts are wrapper templates that surround view content, providing a consistent structure (header, footer, navigation) across pages. The default layout is app/views/layouts/application.html.erb, and all views are rendered inside it by default. The yield keyword inserts the view's content into the layout. Controllers can specify different layouts: layout 'admin' in the controller class, or per action. You can also use content_for/yield pairs for injecting view-specific content (like page titles or per-page JavaScript) into the layout.

Open this question on its own page
40

What is the Rails request-response lifecycle?

A Rails request goes through these steps: 1) Web server (Puma/Nginx) receives the HTTP request. 2) Rack middleware stack processes the request (logging, sessions, CSRF, etc.). 3) Router matches the URL and HTTP verb to a controller action. 4) Controller action runs — calls model methods, assigns instance variables. 5) View renders a template using instance variables from the controller. 6) Response is sent back through the middleware stack to the browser. The whole stack is built on Rack, a Ruby web server interface that standardizes how web servers and frameworks communicate.

Open this question on its own page
41

What is polymorphic association in Rails?

A polymorphic association allows a model to belong to more than one other model type through a single association. Example: a Comment model can belong to both Post and Video. The comments table has two columns: commentable_id (integer) and commentable_type (string, stores the class name like "Post" or "Video"). Declare in the model: belongs_to :commentable, polymorphic: true. In Post: has_many :comments, as: :commentable. Polymorphic associations keep your schema DRY when multiple models share the same associated behavior.

Open this question on its own page
Intermediate 22 questions

Practical knowledge for developers with hands-on experience.

01

What is the N+1 query problem and how do you fix it?

The N+1 query problem occurs when code iterates over N records and makes 1 additional database query per record, resulting in N+1 total queries. Example: @posts.each { |p| puts p.author.name } — 1 query for posts, then N queries for authors. Fix with eager loading: @posts = Post.includes(:author) generates 2 queries regardless of N. Use the Bullet gem to detect N+1 queries in development. Also use eager_load (single LEFT OUTER JOIN) when filtering on association columns, and preload (separate queries) otherwise.

Open this question on its own page
02

What is caching in Rails and what types are available?

Rails supports several caching strategies: Page caching — caches the entire response as a static file (Rails 4+ extracted to a gem). Action caching — caches after running filters (also a gem). Fragment caching — caches portions of views with <% cache @post do %>...<% end %>; the most commonly used. Low-level cachingRails.cache.fetch("key") { expensive_calculation }. SQL caching — automatic within a request (same query twice hits cache). Cache stores: MemoryStore, FileStore, MemCacheStore, RedisCacheStore. Configure with config.cache_store.

Open this question on its own page
03

What is a service object in Rails?

A service object is a Plain Old Ruby Object (PORO) that encapsulates a single business operation or use case, keeping controllers thin and models focused on data concerns. Example: UserRegistrationService.new(params).call handles validation, record creation, email sending, and logging — all in one place. Typically stored in app/services/. Common conventions: a single public call method, a class-level .call shorthand, and returning a result object. Service objects improve testability, readability, and separation of concerns when business logic grows complex.

Open this question on its own page
04

What is a background job in Rails and how is it implemented?

Background jobs run long-running tasks asynchronously outside the request-response cycle (sending emails, processing files, calling external APIs). Rails provides ActiveJob as a framework-agnostic interface for queuing backends. Define: class WelcomeEmailJob < ApplicationJob; def perform(user); UserMailer.welcome(user).deliver_now; end; end. Enqueue: WelcomeEmailJob.perform_later(user). Popular queue adapters: Sidekiq (Redis-backed, fast, concurrent), Resque, DelayedJob (database-backed). Configure in config.active_job.queue_adapter = :sidekiq.

Open this question on its own page
05

What is ActionMailer in Rails?

ActionMailer is the Rails component for sending emails. Mailers are classes in app/mailers/ that inherit from ApplicationMailer. Each method defines an email with mail(to:, subject:), and uses views in app/views/mailer_name/ for HTML and text templates. Send immediately: UserMailer.welcome(@user).deliver_now. Send asynchronously via ActiveJob: UserMailer.welcome(@user).deliver_later. Configure delivery in config/environments/ — use :smtp for production and :test or :letter_opener for development.

Open this question on its own page
06

What is Devise in Rails?

Devise is the most popular authentication gem for Rails, providing a full authentication solution via a set of modular "modules". Core modules: :database_authenticatable (hashed passwords), :registerable (sign up/delete), :recoverable (password reset), :rememberable (remember me cookie), :validatable (email/password validations), :confirmable (email confirmation), :lockable (account locking after failed attempts), :trackable (sign-in stats). Devise generates controllers, views, routes, and migrations. Customize by generating Devise controllers and overriding methods.

Open this question on its own page
07

What is Pundit or CanCanCan in Rails?

Pundit and CanCanCan are popular authorization gems. Pundit uses plain Ruby policy classes (PostPolicy) with methods like update? and destroy? that return true/false. In the controller: authorize @post checks if the current user can perform the action. CanCanCan centralizes authorization in a single Ability class: can :update, Post, user_id: user.id. Check with can?(:update, @post) or authorize! :update, @post. Pundit is preferred for complex, object-level authorization; CanCanCan for simpler role-based access.

Open this question on its own page
08

What is Rails API mode?

Rails API mode creates a stripped-down Rails application optimized for JSON APIs, without views, asset pipeline, cookies, or browser session middleware. Create with rails new myapi --api. Controllers inherit from ActionController::API instead of ActionController::Base, which excludes view rendering and browser-specific middleware. Responses use render json:. Pair with Active Model Serializers or Jbuilder for structured JSON responses, or use jsonapi-serializer for JSON:API compliance. API mode is faster per request and smaller memory footprint than full Rails.

Open this question on its own page
09

What are transactions in ActiveRecord?

ActiveRecord transactions wrap a block of database operations in a single atomic unit — either all succeed or all are rolled back on error. Syntax: ActiveRecord::Base.transaction do ... end or User.transaction do ... end. If an exception is raised inside the block, the transaction is rolled back. Use raise ActiveRecord::Rollback to manually roll back without propagating an exception. Important: only database exceptions trigger automatic rollback — always raise ActiveRecord::Rollback explicitly for business logic failures. Transactions are critical for operations that must be atomic, like transferring funds.

Open this question on its own page
10

What is counter_cache in Rails?

counter_cache is an optimization that stores the count of associated records in a cached column on the parent model, avoiding a COUNT(*) SQL query every time you need the count. Add counter_cache: true to the belongs_to declaration: belongs_to :post, counter_cache: true. Rails maintains a comments_count column on the posts table automatically, incrementing/decrementing it when records are created/destroyed. Access with post.comments.size (uses cache) vs post.comments.count (always hits DB). Add the column via migration: add_column :posts, :comments_count, :integer, default: 0.

Open this question on its own page
11

What is the difference between dependent: :destroy and dependent: :delete_all?

Both options on has_many remove associated records when the parent is deleted, but differently. dependent: :destroy loads each associated record and calls destroy on it — this fires each record's callbacks (before_destroy, after_destroy, dependent associations cascade down). dependent: :delete_all issues a single DELETE FROM table WHERE parent_id = ? SQL statement — much faster but bypasses all callbacks and validations. Use :destroy when you need callbacks to fire (e.g., deleting files, cascading associations). Use :delete_all for simple cleanup of large datasets without side effects.

Open this question on its own page
12

What is Single Table Inheritance (STI) in Rails?

Single Table Inheritance (STI) allows multiple model classes to share a single database table, distinguished by a type column. Example: Employee, Manager, and Developer all inherit from Person and use the people table. Rails stores the class name in the type column. When querying Manager.all, Rails adds WHERE type = 'Manager'. STI works well when subclasses share most attributes. Drawbacks: sparse columns (fields unused by some subclasses), can lead to a wide table. An alternative is polymorphic associations or separate tables.

Open this question on its own page
13

What is ActionCable in Rails?

ActionCable integrates WebSockets into Rails, enabling real-time features. The server maintains persistent connections to clients. You define channels (like controllers for WebSockets) in app/channels/. Clients subscribe to channels via JavaScript. The server broadcasts messages: ActionCable.server.broadcast("notifications_channel", message: "You have a new notification"). ActionCable integrates with Pub/Sub adapters (Redis in production, async in development). Use cases: live chat, notifications, collaborative editing, live sports scores, and real-time dashboards.

Open this question on its own page
14

What is ActiveStorage in Rails?

ActiveStorage handles file uploads and attachments in Rails. Attach files to models: has_one_attached :avatar or has_many_attached :photos. Files can be stored locally, on Amazon S3, Google Cloud Storage, or Azure. Generate transformations: user.avatar.variant(resize_to_limit: [100, 100]) (uses ImageMagick/libvips). In views: <%= image_tag user.avatar %>. Run migrations: rails active_storage:install. ActiveStorage handles direct uploads, streaming, and multipart uploads. It replaced the popular CarrierWave and Paperclip gems as the built-in solution.

Open this question on its own page
15

What is Hotwire and Turbo in modern Rails?

Hotwire (HTML Over The Wire) is Rails 7's approach to building modern, reactive UIs without heavy JavaScript frameworks. Turbo Drive intercepts link clicks and form submissions, replacing page content via fetch without full page reloads. Turbo Frames allow partial page updates — only the framed section is replaced. Turbo Streams enable real-time updates over WebSockets or SSE, allowing the server to push DOM changes (append, replace, remove elements). Stimulus is a lightweight JS framework for adding behavior to HTML. Hotwire lets you build SPAs-like experiences with server-rendered HTML.

Open this question on its own page
16

What is the difference between update_all and update in Rails?

Model.update(id, attrs) finds a record and calls save, running validations and callbacks. records.update_all(column: value) issues a single bulk UPDATE SQL statement for all matching records — it is extremely fast for large datasets but bypasses all validations, callbacks, and timestamps (updated_at is not changed unless explicitly included). Use update_all for batch data migrations, status changes on thousands of records, and anywhere callback overhead is undesirable. Always be cautious — if you need after_update callbacks to fire (e.g., cache invalidation), use individual update calls instead.

Open this question on its own page
17

What is Rails testing (RSpec vs Minitest)?

Rails ships with Minitest as the default testing framework, offering unit tests, functional tests, integration tests, and system tests. It uses a simple assertion-based API. RSpec is a popular alternative BDD framework with a more expressive DSL (describe, context, it, expect, should matchers). The Rails testing stack includes: FactoryBot (fixtures alternative for creating test data), Faker (fake data generation), Shoulda-Matchers (model validation matchers for RSpec), and Capybara (browser simulation for integration/system tests).

Open this question on its own page
18

What is database indexing and why is it important in Rails?

A database index is a data structure that speeds up queries on specific columns at the cost of extra storage and slower writes. Without an index, queries do a full table scan; with an index, they use a B-tree lookup. In Rails migrations: add_index :users, :email or inline: t.string :email, index: true. Always index: foreign keys (Rails 5+ adds these automatically with belongs_to), unique constraint columns (add_index :users, :email, unique: true), and columns frequently used in WHERE clauses or JOINs. Use explain in the console to check if queries use indexes.

Open this question on its own page
19

What is the Rails router's namespace and scope?

namespace groups routes under a URL prefix AND a module prefix. namespace :admin do resources :posts end generates /admin/posts mapped to Admin::PostsController with named routes like admin_posts_path. scope is more flexible — it can add a URL prefix without a module: scope '/admin' do resources :posts end maps to PostsController (no module). scope module: :admin adds module but no URL prefix. Use namespace for fully separated admin sections; use scope when you want URL prefixing without module nesting or vice versa.

Open this question on its own page
20

What is an API versioning strategy in Rails?

Common Rails API versioning approaches: URL versioning/api/v1/users, /api/v2/users using namespaces: namespace :api do namespace :v1 do resources :users end end. Header versioning — version specified via Accept: application/vnd.myapi.v1+json header, parsed in the router or a base controller. Query parameter versioning?version=1. URL versioning is most widely used for its simplicity and cacheability. Create separate controller directories (app/controllers/api/v1/) and serializers per version to allow independent evolution without breaking clients.

Open this question on its own page
21

What are Rails concerns and when should you use them?

Rails concerns (ActiveSupport::Concern) are Ruby modules used to share behavior across multiple models or controllers. They provide included (runs when the module is included) and class_methods (adds class-level methods) DSL. Use concerns when: the same behavior appears in 2+ models (e.g., Searchable, Taggable, Auditable concerns). Avoid concerns when the behavior is only needed in one place (use a plain method), when it hides important logic (making code hard to trace), or when a service object or value object would be a cleaner abstraction. Concerns are not a silver bullet — overuse can create an invisible web of included modules.

Open this question on its own page
22

What is ActiveRecord dirty tracking?

ActiveRecord dirty tracking detects changes to model attributes since they were last saved. Key methods: model.changed? (any unsaved changes?), model.changed (array of changed attribute names), model.changes (hash of attribute → [old, new]), model.name_changed? (was :name changed?), model.name_was (old value), model.name_change ([old, new]). Use in callbacks: before_save { update_slug if name_changed? }. After save, the previous changes are accessible via model.previous_changes. This is implemented by ActiveModel::Dirty, also available in non-ActiveRecord models.

Open this question on its own page
Advanced 13 questions

Deep expertise questions for senior and lead roles.

01

What is metaprogramming in Ruby/Rails and give examples?

Metaprogramming is writing code that writes or modifies code at runtime. Ruby's dynamic nature makes it powerful for metaprogramming. Key techniques: define_method(:foo) { ... } — defines a method dynamically; method_missing — called for undefined methods, used to implement dynamic finders; send(:method_name) — calls any method by name including private; class_eval / module_eval — opens a class to add methods at runtime; attr_accessor is itself a macro that calls define_method. Rails uses metaprogramming extensively — ActiveRecord's associations (has_many), validations (validates), and callbacks are all macros implemented via metaprogramming.

Open this question on its own page
02

What is the difference between include, extend, and prepend in Ruby?

include mixes a module's methods into the class as instance methods and inserts the module into the class's ancestor chain after the class. extend adds a module's methods as class methods (extends the singleton class). prepend inserts the module before the class in the ancestor chain, so the module's methods are called first — allowing you to wrap or override methods without aliasing. Rails' ActiveSupport::Concern uses prepend internally. Example: prepend is used to add instrumentation around existing methods by calling super from within the module method.

Open this question on its own page
03

How does Rails handle database connection pooling?

Rails uses connection pooling to reuse database connections efficiently. A pool of connections is maintained per database per process. The pool size is configured in database.yml via the pool option (default: 5). When a thread needs a connection, it checks one out from the pool; when done, it checks it back in. Active Record connection adapter manages this via ActiveRecord::ConnectionAdapters::ConnectionPool. If all connections are in use and a new request arrives, it waits up to checkout_timeout seconds (default: 5). For Puma (multi-threaded), set pool size ≥ number of threads. Use with_connection in background threads to ensure proper checkout/checkin.

Open this question on its own page
04

What is Rack and how does Rails relate to it?

Rack is a minimal, modular Ruby web server interface specification. A Rack application is any Ruby object that responds to call(env) and returns a 3-element array: [status, headers, body]. Rails is a Rack application. The Rack middleware stack is a chain of Rack apps where each passes the request to the next. Run rails middleware to see the full stack. Each middleware layer handles a cross-cutting concern: sessions, logging, CSRF protection, asset serving, request tracing. You can add custom middleware: config.middleware.use MyMiddleware. This architecture allows sharing middleware between Rails, Sinatra, and any Rack-compatible framework.

Open this question on its own page
05

What is query optimization with explain in Rails?

ActiveRecord's explain method runs EXPLAIN (or EXPLAIN ANALYZE in PostgreSQL) on the generated SQL and returns the query execution plan. Usage: User.where(active: true).explain. The output shows whether the database uses an index scan or a full sequential scan. Look for: Seq Scan (bad for large tables — add an index), Index Scan or Index Only Scan (good), and actual vs. estimated row counts. For complex queries, EXPLAIN ANALYZE shows actual execution time per node. Combine with the PgHero gem or rack-mini-profiler to identify slow queries in development and production.

Open this question on its own page
06

What are Rails engines and how are they used?

A Rails engine is a self-contained mini-application that can be mounted inside a Rails app, providing isolated controllers, models, views, migrations, and routes. rails plugin new my_engine --mountable creates a mountable engine. Mount with: mount MyEngine::Engine, at: '/my_engine' in the host app's routes. Engines are used to package reusable functionality — Devise, ActiveAdmin, Spree Commerce, and Sidekiq's web UI are all engines. Namespacing prevents class name collisions. Shared tables are handled via isolate_namespace. Engines can have their own migrations, which the host app runs separately.

Open this question on its own page
07

What is the difference between class methods and instance methods in ActiveRecord?

In ActiveRecord, class methods are called on the model class itself and typically return a relation or perform bulk operations: User.active (scope), User.count, User.create(...). They are defined with def self.method_name or inside class << self. Instance methods are called on a specific record object: user.full_name, user.save, user.destroy. Knowing this distinction matters for scopes (always class methods returning relations), callbacks (instance methods called on the object), and association methods. A common mistake is accidentally calling a class method on an instance or vice versa, which raises a NoMethodError.

Open this question on its own page
08

What is optimistic vs pessimistic locking in Rails?

Optimistic locking assumes conflicts are rare — multiple users can read the same record simultaneously. When saving, Rails checks a lock_version integer column; if another user already updated the record, it raises ActiveRecord::StaleObjectError, which you rescue and retry. Enable by adding a lock_version column. Pessimistic locking acquires a database-level lock preventing other transactions from reading or writing: User.lock.find(id) issues SELECT ... FOR UPDATE. Use pessimistic locking for financial transactions where stale reads are unacceptable. Use optimistic locking for high-read, low-conflict scenarios like CMS editing.

Open this question on its own page
09

What is ActiveRecord's STI vs polymorphic associations — when to use each?

STI shares one table for multiple subclasses — best when subclasses have the same attributes and differ primarily in behavior. Example: Animal table with Dog and Cat subclasses. Polymorphic associations allow one model to belong to multiple unrelated parent types — best when unrelated models share an associated behavior. Example: both Post and Video can have Comments. Key decision: if subclasses share data structure → STI; if a child model needs to reference multiple unrelated parent types → polymorphic. Neither is ideal for complex hierarchies — consider Multiple Table Inheritance (MTI) via gems or a separate mapping table instead.

Open this question on its own page
10

How do you handle background job failures and retries in Rails?

ActiveJob provides hooks for handling failures: rescue_from(StandardError) { |e| retry_job(wait: 5.minutes) }. Sidekiq has built-in retry logic with exponential backoff — it retries failed jobs up to 25 times by default, with increasing delays, then moves them to the Dead Job Queue (viewable in the Sidekiq Web UI). Custom retry logic: sidekiq_options retry: 5. For critical jobs, use idempotency — jobs should be safe to run multiple times without side effects (check if work was already done). For non-retriable jobs: sidekiq_options retry: false. Monitor with Sidekiq metrics, error tracking services (Sentry/Honeybadger), and alerting on Dead Queue size.

Open this question on its own page
11

What is database sharding in the context of Rails?

Sharding horizontally partitions data across multiple databases based on a key (e.g., user ID), with each shard holding a subset of the data. Rails 6.1+ introduced first-class horizontal sharding support via ActiveRecord::Base.connected_to(shard: :shard_one) { ... }. Configure shards in database.yml. A shard resolver determines which shard to connect to for a given request. Sharding solves write scalability (each shard handles only a portion of writes) and can keep data geographically close to users. Challenges: cross-shard queries are complex, schema changes must be applied to all shards, and re-sharding existing data is painful.

Open this question on its own page
12

What is the Observer pattern in Rails and is it still used?

Rails once included ActiveRecord::Observer — a way to watch model lifecycle events from a separate class, reducing callback clutter in models. Example: class UserObserver < ActiveRecord::Observer; def after_create(user); Mailer.welcome(user).deliver; end; end. Observers were extracted to the rails-observers gem in Rails 4 and are no longer in Rails core. Modern alternatives: use callbacks sparingly in models (only for intrinsic model concerns), service objects for cross-cutting operations, event systems (Wisper, dry-events) for decoupled pub/sub, or ActiveSupport::Notifications for instrumenting and subscribing to app events.

Open this question on its own page
13

What is the role of Puma in Rails deployment?

Puma is Rails' default web server (since Rails 5). It is a concurrent, multi-threaded Rack server designed for production. Key features: multi-threaded (handles multiple requests per process simultaneously using threads — allows connection pool sharing), cluster mode (multiple worker processes, each multi-threaded — called "workers" + "threads"), and socket binding (can listen on TCP or Unix sockets). Configure via config/puma.rb: workers ENV.fetch("WEB_CONCURRENCY") { 2 }; threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }. In production, Puma sits behind Nginx (reverse proxy + static file serving). Puma handles graceful restarts (phased-restart) for zero-downtime deploys.

Open this question on its own page
Back to All Topics 76 questions total