- Ruby on Rails Technical Interview Questions:
- Basic
- 1. What is MVC?
- Example:
- 2. What is ActiveRecord?
- 3. What are callbacks in Rails?
- 4. What is mass assignment?
- 5. What is CSRF?
- 6. How do you handle database migrations in Rails?
- 7. What is a scope?
- 8. What is the difference between has_one and belongs_to?
- 9. What is Rails Console, and how do you use it?
- 10. What are before_action, after_action, and skip_before_action?
- 11. What are Strong Parameters? Why are they needed?
- 12. How do you define routes in Rails?
- 13. How do you generate a model, controller, and migration in Rails?
- 14. What is the config/routes.rb file used for?
- 15. What is flash in Rails? How is it different from session?
- 16. How does Rails handle sessions and cookies?
- 17. What is link_to in Rails views?
- 18. What is form_with, and how does it work?
- 19. What is partial in Rails views?
- 20. What is link_to in Rails views?
- 21. What is form_with, and how does it work?
- 22. What is a partial in Rails views?
- 23. What is layout in Rails, and how do you use it?
- 24. What is yield, and how does it work in Rails layouts?
- 25. What are helpers in Rails?
- 26. What is params in Rails, and how does it work?
- 27. What is the difference between GET, POST, PUT, and DELETE requests in Rails?
- 28. What is rails routes, and how do you use it?
- 29. What is has_many :through, and when do you use it?
- 30. What is validates in Rails models?
- 31. What is rescue_from, and how does it work?
- 32. What is rake, and how does it work in Rails?
- 🛠 1. Handling N+1 Queries (Optimization)
- 🛠 2. Implementing Caching in Rails
- 5. When to Use Proc vs. Lambda
- 6. Real-World Use Cases
- Summary
- Explain Sharding ?
- Why Use Sharding?
- ✅ Benefits of Sharding
- How Does Sharding Work in Rails?
- 🔹 Implementing Sharding in Rails
- When to Use Sharding?
- 🛠 Core Rails Questions
- How does Rails handle database connection pooling?
- Explain the difference between joins, includes, preload, and eager_load.
- How does Rails’ autoloading work? What changed in Zeitwerk?
- What are ActiveRecord callbacks? When should you avoid them?
- What are ActiveSupport Concerns? How do they differ from modules?
- What is the purpose of Rails engines? When would you use one?
- How does Rails handle has_many :through vs. has_and_belongs_to_many?
- What’s the difference between belongs_to and has_one?
- What are Rails observers, and why are they deprecated?
- How does the Rails asset pipeline work?
- What are different ways to manage configurations in Rails (secrets.yml, credentials.yml.enc, ENV variables)?
- What is the difference between dependent: :destroy, dependent: :delete_all, and dependent: :nullify?
- How do you implement state machines in Rails (e.g., AASM, workflow gem)?
- What’s the difference between rake and rails commands?
- What are concerns, and when should they be used?
- ⚡ Performance & Scalability
- What techniques do you use to prevent N+1 queries?
- What is database sharding? How does Rails support it?
- How do you analyze slow database queries in Rails?
- What is caching in Rails? How does fragment caching work?
- How do you handle background jobs at scale in Rails?
- What are the advantages and disadvantages of Sidekiq vs. Delayed Job vs. Resque?
- What is a Rails middleware? How do you add a custom middleware?
- How do you scale a Rails application to handle high traffic?
- What are different types of caching available in Rails?
- What is Puma? How does it improve Rails performance?
- How does Rails handle HTTP/2 and WebSockets?
- What are the best practices for optimizing ActiveRecord queries?
- What’s the difference between connection_pool and database.yml settings?
- How do you handle large file uploads in Rails?
- What’s the difference between synchronous and asynchronous processing in Rails?
- 🛡️ Security & Best Practices
- What is CSRF, and how does Rails prevent it?
- What is SQL injection? How does Rails prevent it?
- How does Rails handle Cross-Site Scripting (XSS) vulnerabilities?
- What is mass assignment, and how can it be prevented?
- What is the difference between strong_parameters and attr_accessible?
- What is session fixation, and how does Rails mitigate it?
- What is secure_compare and why is it important?
- How do you prevent brute-force attacks in Rails authentication?
- How does Devise handle authentication and security?
- What are Rails' default security mechanisms (e.g., Secure Headers, HTTP-only cookies)?
- How do you enforce password policies in Rails apps?
- What is parameter tampering, and how does Rails prevent it?
- How do you secure Rails APIs (rate limiting, JWT, OAuth)?
- What is the difference between session_store and cookie_store?
- What is CORS, and how does Rails handle it?
- What is permanent_signed vs. signed cookies in Rails?
- How do you handle authorization (Pundit vs. CanCanCan)?
- How do you prevent replay attacks in Rails?
- What is rails-ujs, and how does it help with security?
- How do you enforce HTTPS in a Rails application?
- 🛠 System Design & Architecture
- What is REST, and how does Rails enforce RESTful design?
- How do you implement API versioning in Rails?
- What are the key differences between REST and GraphQL?
- How would you design a multi-tenant Rails application?
- How does Rails handle WebSockets and real-time features?
- How do you design a microservices-based architecture with Rails?
- What are the trade-offs of monolithic vs. microservices architecture in Rails?
- What are design considerations for building a large-scale Rails API?
- How do you handle background jobs in a multi-server environment?
- How do you handle file storage in Rails (ActiveStorage, Shrine, Paperclip)?
- What is CQRS, and how can it be applied in Rails applications?
- How do you handle rate-limiting in Rails APIs?
- What are the challenges of running Rails in a containerized environment (Docker, Kubernetes)?
- How would you handle real-time notifications in Rails?
- How do you implement event-driven architecture in Rails?
- What are the key performance bottlenecks in a Rails application?
- What are the key differences between Rails and other frameworks like Django or Laravel?
- How do you handle service-to-service authentication in a Rails microservices setup?
- How do you optimize database indexes for large-scale Rails applications?
- How would you design a rate-limiting system in Rails?🛠 System Design & Architecture
- What is REST, and how does Rails enforce RESTful design?
- How do you implement API versioning in Rails?
- What are the key differences between REST and GraphQL?
- How would you design a multi-tenant Rails application?
- How does Rails handle WebSockets and real-time features?
- How do you design a microservices-based architecture with Rails?
- What are the trade-offs of monolithic vs. microservices architecture in Rails?
- What are design considerations for building a large-scale Rails API?
- How do you handle background jobs in a multi-server environment?
- How do you handle file storage in Rails (ActiveStorage, Shrine, Paperclip)?
- What is CQRS, and how can it be applied in Rails applications?
- How do you handle rate-limiting in Rails APIs?
- What are the challenges of running Rails in a containerized environment (Docker, Kubernetes)?
- How would you handle real-time notifications in Rails?
- How do you implement event-driven architecture in Rails?
- What are the key performance bottlenecks in a Rails application?
- What are the key differences between Rails and other frameworks like Django or Laravel?
- How do you handle service-to-service authentication in a Rails microservices setup?
- How do you optimize database indexes for large-scale Rails applications?
- How would you design a rate-limiting system in Rails?
- 💎 Advanced Ruby Questions
- What is the difference between Proc and Lambda?
- What is the difference between include, extend, and prepend?
- How does Ruby garbage collection (GC) work?
- What is the difference between Thread and Fiber?
- What are Ruby metaprogramming techniques?
- What are method_missing and respond_to_missing?
- What are singleton classes and eigenclasses in Ruby?
- What is duck typing in Ruby?
- How does Ruby handle method lookup and method resolution order (MRO)?
- How does module_function work in Ruby?
- What is the difference between public, private, and protected methods?
- What is the difference between class_variable, instance_variable, and global_variable?
- What is monkey patching, and when should you avoid it?
- What are refinements in Ruby?
- How do you implement multiple inheritance in Ruby?
- What is the difference between super and self?
- How does define_method work in Ruby?
- What is method_missing, and how can it be useful?
- What is a Ruby block, and how is it different from a Proc?
- What is the difference between tap, yield_self, and then in Ruby?
- Core Ruby Questions
- 🧩 OOP and Design Questions
- What are the SOLID principles? Can you demonstrate one using Ruby?
- What’s the difference between a class variable and a class instance variable?
- When would you use method_missing vs define_method?
- How do modules affect the method lookup chain in Ruby?
- What is a mixin and when would you use it over inheritance?
- 🧪 Testing and Tooling
- 🔀 Enumerable and Functional Patterns
- 🧬 Metaprogramming & DSLs
- What are the risks of using eval in Ruby?
- Can you write a DSL for a pizza builder? (e.g., Pizza.new.size(:large).toppings(:olives, :cheese))
- How does method_missing affect performance and debuggability?
- When would you use class_eval vs define_singleton_method?
- Can you override send or respond_to?? When might you do that?
- 🕹 Concurrency and System Design
- 💡 Debugging and Performance
- 🔐 Trick Questions / Gotchas
- ✅ Basic Ruby Questions
- What are symbols in Ruby? How are they different from strings?
- What are the different types of variables in Ruby (local, instance, class, global)?
- What is the difference between ==, eql?, and equal??
- Explain the difference between puts, print, and p.
- What is a block, and how is it different from a Proc or a lambda?
- What is the use of the self keyword in Ruby?
- What is the difference between include and extend in modules?
- How does garbage collection work in Ruby?
- What’s the difference between nil, false, and undefined variable in Ruby?
- 🔁 Intermediate Ruby Questions
- Explain how Ruby handles method overloading or default arguments.
- What is duck typing in Ruby? Give an example.
- How does Ruby handle inheritance and method resolution?
- What are singleton methods? When would you use them?
- What’s the difference between Proc.new, lambda, and the -> syntax?
- What are refinements in Ruby? Why would you use them instead of monkey-patching?
- What are the scopes of constants in Ruby (e.g., ::, nesting)?
- Explain what mixins are. How are they implemented in Ruby?
- How do you define and use custom enumerators in Ruby?
- 🔬 Advanced Ruby Questions
- How would you implement your own version of each, map, or select without using Ruby's built-in methods?
- What are some metaprogramming techniques in Ruby? Show an example using define_method or method_missing.
- What is the difference between class variables (@@) and class instance variables (@ on the class)?
- How does Ruby’s method_missing work, and what are the risks?
- What’s the difference between eager and lazy enumerators in Ruby?
- How do fibers work in Ruby? What are they useful for?
- How would you optimize memory usage in a Ruby app that processes millions of records?
- What is the Global Interpreter Lock (GIL) in Ruby MRI? How does it affect threading?
- How would you implement a Domain-Specific Language (DSL) in Ruby?
- 📌 Live Coding Challenge Questions
- Implement a caching mechanism in Rails without using built-in Rails caching.
- Optimize a slow SQL query in a Rails application.
- Write a background job that sends scheduled emails using Sidekiq.
- Write a Rails service object that processes and validates a CSV file upload.
- Refactor a Rails controller that has too many instance variables.
- Write a Rails middleware that logs request details before passing it to the controller.
- Write a method that finds all duplicate users based on their email in ActiveRecord.
- Design a system to throttle API requests in Rails without using third-party gems.
- Implement an authentication system without Devise in Rails.
- Write a custom ActiveRecord scope that returns all users who haven’t logged in for 30 days.
- 𝗜𝗻𝘁𝗲𝗿𝗺𝗲𝗱𝗶𝗮𝘁𝗲 𝗤𝘂𝗲𝘀𝘁𝗶𝗼𝗻𝘀 -:
- 1. How do you handle exceptions and errors in Rails? What strategies do you use for logging and notification?
- 2. How do you approach database modeling in Rails? What considerations do you take for efficient data retrieval and storage?
- 3. How do you use Rails migrations to manage database schema changes? What are some best practices for writing migrations?
- 4. What caching mechanisms does Rails offer (fragment, action, and page caching), and when would you use each?
- 5. How do you design RESTful APIs in Rails? What considerations do you take for API versioning and security?
- 6. How do you use service objects to encapsulate business logic in Rails? What benefits do they offer?
- 7. How do you define nested routes in Rails? What are some advanced routing techniques such as shallow routes?
- 8. Explain polymorphic associations in Rails. When would you choose them over standard associations?
- 𝗔𝗱𝘃𝗮𝗻𝗰𝗲𝗱 𝗤𝘂𝗲𝘀𝘁𝗶𝗼𝗻𝘀 -:
- 9. How do you tackle the N+1 query problem in Rails? What tools or techniques do you use to optimize queries?
- 10. How do you handle database transactions in Rails? What steps do you take to optimize database performance through indexing and query tuning?
- 11. How would you manage caching in a high-traffic, distributed Rails environment? Discuss the use of fragment, action, and page caching.
- 12. Discuss Rails’ built-in security features. How do you mitigate risks like CSRF, XSS, and SQL injection?
- 13. How do you design, secure, and version API endpoints in Rails? What are your thoughts on REST vs. GraphQL?
- 14. What architectural patterns have you implemented to ensure a Rails application scales? Discuss multi-tenancy or micro-services if applicable.
- 15. How do you address concurrency in Rails? Have you encountered and solved challenges with multi-threading?
- 16. What is sharding, and how can it be implemented in Rails to optimise data access for large datasets?
- 17. What testing frameworks and strategies (unit, integration, performance) do you rely on in Rails? How do you ensure comprehensive test coverage?
- 18. Describe your experience implementing real-time features using Action Cable. What challenges did you encounter?
- 19. How do you approach refactoring a large, legacy Rails codebase without causing disruptions? What tools or methodologies do you use?
- 20. Have you worked with Rails 6/7 features such as ActionMailbox, ActionText, or Hotwire? How have they influenced your development process?
- 21. How do you use service objects or decorators to encapsulate business logic? Share your experiences with Ruby’s meta-programming capabilities.
- 22. What role does Rack play in Rails? Have you ever built custom middleware? If so, how?
- 23. How do you analyze and optimize database queries in Rails? What tools do you use to identify performance bottlenecks?
- How does Rails handle database connection pooling?
- Explain the difference between joins, includes, preload, and eager_load.
- How does Rails’ autoloading work? What changed in Zeitwerk?
- What are ActiveRecord callbacks? When should you avoid them?
- What are ActiveSupport Concerns? How do they differ from modules?
- What is the purpose of Rails engines? When would you use one?
- How does Rails handle has_many :through vs. has_and_belongs_to_many?
- What’s the difference between belongs_to and has_one?
- What are Rails observers, and why are they deprecated?
- How does the Rails asset pipeline work?
- What are different ways to manage configurations in Rails (secrets.yml, credentials.yml.enc, ENV variables)?
- What is the difference between dependent: :destroy, dependent: :delete_all, and dependent: :nullify?
- How do you implement state machines in Rails (e.g., AASM, workflow gem)?
- What’s the difference between rake and rails commands?
- What are concerns, and when should they be used?
- 🧠 Problem 1: Dynamic Method Generation (Metaprogramming)
- 🧠 Problem 2: Lazy Prime Generator (Enumerators)
- 🧠 Problem 3: Safe Concurrency with Threads
- 🚀 Intermediate Rails Questions
- 1. Handling Exceptions & Logging
- 2. Database Modeling Considerations
- 3. Managing Migrations
- 4. Caching Mechanisms
- 5. RESTful API Design
- 6. Service Objects for Business Logic
- 7. Nested Routes & Advanced Routing
- 9. N+1 Query Problem & Optimization
- 11. Caching in a Distributed Rails App
- 12. Rails Security
- 14. Scaling Rails
- 15. Handling Concurrency
- 16. Sharding in Rails
- 17. Rails Testing
- 18. Real-Time Features (ActionCable)
- 19. Refactoring Legacy Rails Code
- 20. Rails 6/7 Features
- Ruby-Specific Questions
- Final Questions
- Basic
MVC stands for Model-View-Controller. It is a design pattern used in Rails to separate concerns in an application:
- Model: Represents the data and business logic of the application. It interacts with the database to retrieve and store information.
- View: The presentation layer that displays the data to the user. It is typically HTML or JSON for web apps.
- Controller: Acts as an intermediary between the Model and View. It processes user input, calls the necessary model methods, and renders the appropriate view.
# Model
class Post < ApplicationRecord
validates :title, presence: true
end
# Controller
class PostsController < ApplicationController
def show
@post = Post.find(params[:id])
end
end
# View (show.html.erb)
<h1><%= @post.title %></h1>
<p><%= @post.body %></p>
ActiveRecord is the Object-Relational Mapping (ORM) layer in Rails that facilitates communication between the application and the database. It maps database tables to Ruby classes, allowing you to interact with the database using Ruby objects.
ActiveRecord automatically handles CRUD operations. It allows you to query, insert, update, and delete database records without needing to write raw SQL. Example:
# Finding a record
user = User.find(1)
# Creating a new record
user = User.create(name: "John", email: "john@example.com")
# Updating a record
user.update(name: "John Doe")
# Deleting a record
user.destroy
Callbacks in Rails are methods that get called at certain points of an object's lifecycle. They allow you to hook into and modify the behavior of ActiveRecord objects before or after certain events, such as saving, updating, or destroying records.
Common Callbacks: before_save, after_save before_create, after_create before_update, after_update before_destroy, after_destroy Example:
class Post < ApplicationRecord
before_save :set_default_title
private
def set_default_title
self.title = "Untitled" if title.blank?
end
end
Mass assignment occurs when you assign values to multiple attributes of an object at once, typically using the update or create methods. This is a feature in Rails that lets you assign values to several attributes in a single step.
Mass assignment vulnerability occurs when an attacker can update attributes that they shouldn't be allowed to, such as sensitive fields.
Example of mass assignment:
# Allowed attributes: name, email
user = User.new(name: "John", email: "john@example.com", admin: true) # admin should not be assignable!
Follow-up: How do you protect your app against it?
You can prevent mass assignment vulnerabilities by using strong parameters in Rails, which explicitly define which attributes are allowed to be mass-assigned.
class UsersController < ApplicationController
def user_params
params.require(:user).permit(:name, :email) # Only allow name and email
end
end
Cross-Site Request Forgery (CSRF) is an attack where a malicious website can send unauthorized requests to a web application where the user is already authenticated. It tricks the user into performing an unintended action.
Follow-up: How is it handled in Rails? Rails protects against CSRF by using a CSRF token. This token is generated on each form and ensures that the request came from your site and not from an external source.
Rails includes the token in every form by default, and it’s checked on form submissions.
Example:
<%= form_with(url: posts_path, method: :post) do %>
<%= text_field_tag :title %>
<%= submit_tag "Create Post" %>
<% end %>
Rails automatically includes a hidden CSRF token in forms generated by form_with.
Database migrations in Rails are used to manage changes to the database schema over time. They allow you to version-control your database structure, making it easy to roll back or apply changes.
Migrations are stored in files in the db/migrate directory. They can be run using rails db:migrate. Example:
# Migration to add a title column to the posts table
class AddTitleToPosts < ActiveRecord::Migration[6.0]
def change
add_column :posts, :title, :string
end
end
Run the migration:
rails db:migrate
A scope in Rails is a way to define commonly-used queries that can be reused throughout the application. It’s defined within the model and is typically used to simplify querying the database.
Example:
class Post < ApplicationRecord
scope :published, -> { where(published: true) }
scope :recent, -> { order(created_at: :desc).limit(5) }
end
# Usage
Post.published.recent
has_one: This association indicates that one object can have one related object. It is typically used on the "one" side of a relationship. belongs_to: This association indicates that an object belongs to another object. It is used on the "many" side of the relationship. Example:
class Author < ApplicationRecord
has_one :profile # Author has one profile
end
class Profile < ApplicationRecord
belongs_to :author # Profile belongs to an author
end
In this case, an Author has one Profile, and a Profile belongs to an Author.
The Rails Console (rails console or rails c) is an interactive REPL (Read-Eval-Print Loop) that allows developers to run Ruby and Rails commands inside an application’s environment.
Usage:
rails console # Start console in default (development) mode
rails console --sandbox # Run console with changes rolled back after exit
rails console production # Start console in production environment
Example:
# Create a new user
user = User.create(name: "Alice", email: "alice@example.com")
# Find a user
user = User.find_by(email: "alice@example.com")
# Update a user
user.update(name: "Alice Doe")
# Delete a user
user.destroy
etc
These controller filters in Rails run specific code before or after an action.
before_action
Runs before the controller action.
class ArticlesController < ApplicationController
before_action :authenticate_user
def index
@articles = Article.all
end
private
def authenticate_user
redirect_to login_path unless current_user
end
end
after_action
Runs after the action is executed.
class ArticlesController < ApplicationController
after_action :log_activity
def show
@article = Article.find(params[:id])
end
private
def log_activity
Rails.logger.info("Article viewed at #{Time.now}")
end
end
skip_before_action
Skips the execution of a before_action for certain actions.
class ArticlesController < ApplicationController
before_action :authenticate_user
skip_before_action :authenticate_user, only: [:index, :show]
def index
@articles = Article.all
end
end
Strong parameters prevent mass assignment vulnerabilities by requiring attributes to be explicitly permitted.
Unsafe (Vulnerable to Mass Assignment Attack)
user = User.new(params[:user]) # An attacker can set `admin: true`
Safe Approach (Strong Parameters)
class UsersController < ApplicationController
def create
@user = User.new(user_params)
@user.save
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
Routes define URL patterns and corresponding controller actions.
Basic Routes (config/routes.rb):
Rails.application.routes.draw do
get "/articles", to: "articles#index"
post "/articles", to: "articles#create"
get "/articles/:id", to: "articles#show", as: "article"
end
Follow-up: What is the difference between resources and resource?
Method Routes Generated Example
resources :users Creates 7 RESTful routes (index, show, new, create, , update, destroy) GET /users/:id/
resource :profile Creates only one route per action (no index route) GET /profile/
Model:
rails generate model User name:string email:string
Creates:
app/models/user.rb
db/migrate/xxxx_create_users.rb
Controller:
rails generate controller Users index show
Creates:
app/controllers/users_controller.rb
app/views/users/index.html.erb
app/views/users/show.html.erb
Migration:
rails generate migration AddAgeToUsers age:integer
rails db:migrate
This file defines all application routes that map URLs to controllers and actions.
Example:
Rails.application.routes.draw do
root "home#index"
resources :articles
end
root "home#index" → Homepage
resources :articles → Generates RESTful routes
What is the difference between render, redirect_to, and respond_to in controllers?
Method Purpose Example
render Renders a template render "show"
redirect_to Redirects to another URL redirect_to articles_path
respond_to Responds with different formats (HTML, JSON) `respond_to {
Flash Stores temporary messages that last one request. Commonly used for notifications.
flash[:notice] = "Article saved!"
redirect_to articles_path
Session
Stores data across multiple requests.
Used for user authentication.
session[:user_id] = @user.id
Session stores data server-side (e.g., in cookies or Redis). Cookies store small amounts of client-side data.
Example (Using Sessions):
session[:user_id] = @user.id
Example (Using Cookies):
cookies[:user_id] = { value: @user.id, expires: 1.week.from_now }
Used to generate HTML tags dynamically.
<%= link_to "Home", root_path %>
Follow-up: How can you make link_to submit a form?
<%= link_to "Delete", article_path(@article), method: :delete, data: { confirm: "Are you sure?" } %>
Used to generate forms dynamically in Rails.
<%= form_with model: @article, local: true do |f| %>
<%= f.text_field :title %>
<%= f.submit "Save" %>
<% end %>
A partial is a reusable view component.
Usage:
<%= render "shared/header" %>
Follow-up: How do you pass local variables to a partial?
<%= render "article", article: @article %>
Partial _article.html.erb:
<h2><%= article.title %></h2>
link_to is a Rails helper method that generates HTML anchor () tags dynamically.
Basic Usage:
<%= link_to "Home", root_path %>
Generates:
<a href="/">Home</a>
Follow-up: How can you make link_to submit a form?
link_to can be used to send DELETE/POST/PUT requests by specifying the method and adding data: { confirm: "Message" }.
<%= link_to "Delete", article_path(@article), method: :delete, data: { confirm: "Are you sure?" } %>
Generates:
<a href="/articles/1" data-method="delete" data-confirm="Are you sure?">Delete</a>
Rails uses JavaScript (UJS) to convert this into a DELETE request.
form_with is a Rails helper used to generate forms dynamically.
Basic Example:
<%= form_with model: @article, local: true do |f| %>
<%= f.text_field :title %>
<%= f.submit "Save" %>
<% end %>
This generates:
<form action="/articles" method="post">
<input type="text" name="article[title]">
<input type="submit" value="Save">
</form>
local: true prevents AJAX submissions.
A partial is a reusable view component that helps avoid duplication.
Example: Create _article.html.erb:
<div class="article">
<h2><%= article.title %></h2>
<p><%= article.content %></p>
</div>
Use it in another view:
<%= render "article", article: @article %>
Follow-up: How do you pass local variables to a partial?
<%= render "article", article: @article %>
Inside _article.html.erb:
<h2><%= article.title %></h2>
Layouts define a common structure for multiple views.
Example app/views/layouts/application.html.erb:
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
</head>
<body>
<%= yield %>
</body>
</html>
Each view injects its content into <%= yield %>.
yield acts as a placeholder for page-specific content inside a layout.
Example app/views/layouts/application.html.erb:
<html>
<head><title>My App</title></head>
<body>
<%= yield %> <!-- Page-specific content goes here -->
</body>
</html>
Usage in app/views/articles/index.html.erb:
<h1>All Articles</h1>
Final Rendered Output:
<html>
<head><title>My App</title></head>
<body>
<h1>All Articles</h1>
</body>
</html>
Helpers are Ruby methods used in views to keep logic out of templates.
Example Helper (app/helpers/articles_helper.rb):
module ArticlesHelper
def formatted_date(date)
date.strftime("%B %d, %Y")
end
end
Usage in a view:
<p>Published on <%= formatted_date(@article.created_at) %></p>
Follow-up: When should you use a helper vs. a partial?
Use Case Helper Partial Formatting data ✅ Yes ❌ No Repeating view elements ❌ No ✅ Yes
params stores request data (e.g., form inputs, URL parameters).
Example Controller:
class ArticlesController < ApplicationController
def show
@article = Article.find(params[:id]) # Fetch from URL
end
def create
@article = Article.new(params.require(:article).permit(:title, :content)) # Form Data
end
end
HTTP Method Purpose Example Usage GET Read data GET /articles/1 POST Create data POST /articles PUT Update entire record PUT /articles/1 DELETE Delete a record DELETE /articles/1
Lists all available routes in a Rails app.
rails routes
Example Output:
articles GET /articles(.:format) articles#index
It sets up a many-to-many relationship via a join table.
class User < ApplicationRecord
has_many :user_projects
has_many :projects, through: :user_projects
end
class UserProject < ApplicationRecord
belongs_to :user
belongs_to :project
end
class Project < ApplicationRecord
has_many :user_projects
has_many :users, through: :user_projects
end
validates ensures data integrity before saving records.
class User < ApplicationRecord
validates :name, presence: true, length: { minimum: 3 }
validates :email, uniqueness: true
end
Follow-up: What are some common validation options?
Validation Example
presence: true Ensures value is present
uniqueness: true Ensures unique values
length: { minimum: x } Min character length
format: { with: /regex/ } Custom regex validation
rescue_from handles exceptions globally in controllers.
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, with: :not_found
private
def not_found
render plain: "404 Not Found", status: :not_found
end
end
Rake (Ruby Make) automates tasks like migrations and seeding.
rake db:migrate
rake db:seed
Follow-up: What is the difference between rake and rails commands?
Command Purpose
rake Runs tasks (e.g., migrations)
rails Runs commands (e.g., server, console)
To handle N+1 queries in Rails, We typically use eager loading with includes, preload, or eager_load. This ensures that associated records are fetched in a single query rather than one per record.
❌ Problem:
# N+1 Issue
Post.all.each do |post|
puts post.comments.count
end
users = User.all
users.each do |user|
puts user.posts.count
end
This results in one query per user, leading to an N+1 query issue.
✅ Solution: Use includes for Eager Loading
users = User.includes(:posts) # Fetch users & posts in 1 query
users.each do |user|
puts user.posts.count # Does not make extra queries
end
# Optimized with eager loading
Post.includes(:comments).each do |post|
puts post.comments.count
end
👉 includes loads the associated records efficiently.
preload:
Use when: You want to load the associations in a separate query (good for simple display, not for SQL conditions on joined tables).
# This will run two queries:
# 1. SELECT * FROM posts
# 2. SELECT * FROM comments WHERE post_id IN (...)
posts = Post.preload(:comments)
posts.each do |post|
post.comments.each do |comment|
puts comment.body
end
end
eager_load:
Use when: You want to avoid N+1 and also filter or sort based on associated table columns using a single SQL query with a JOIN.
# This performs a LEFT OUTER JOIN in one SQL query
posts = Post.eager_load(:comments).where("comments.created_at > ?", 1.week.ago)
posts.each do |post|
post.comments.each do |comment|
puts comment.body
end
end
This is helpful when the query involves conditions on the joined table (comments), and Rails handles the LEFT OUTER JOIN automatically.
Summary:
Method Type of Query Use Case
includes Smartly chooses join/preload Safe default for most use cases
preload Separate queries Display data without filtering/sorting on join
eager_load Single joined query Needed when filtering/sorting using joined table
🔹 Fragment Caching
Use case: You want to cache a specific section of the view, like a post card or sidebar, to avoid rendering it again and again.
How it works:
Rails generates a cache key for the object (like views/posts/123-20250422113000) based on its class, ID, and updated_at timestamp. If the key exists in the cache store, it reuses the HTML output instead of rerendering.
Cache key tip:
Rails automatically uses cache_key_with_version (e.g., posts/123-20250422120000) so you don’t need to manually manage invalidation unless you have custom logic.
- cache @post do
.post
%h2= @post.title
%p= @post.body
Best practices:
Use meaningful keys if you're caching non-record-based content:
- cache ['sidebar', current_user.role] do
= render 'shared/sidebar'
🔹 Russian Doll Caching:
Use case:
Your view has multiple nested partials (e.g., posts with comments), and you want to cache each layer separately to avoid cache invalidation of the entire block.
Why it's powerful:
If a comment changes, only the comment block cache is invalidated, not the entire post. Rails handles this efficiently using cache keys with timestamps.
- cache @post do
.post
%h2= @post.title
%p= @post.body
- cache @post.comments do
.comments
= render @post.comments
In the above example:
If @post.updated_at changes → outer cache invalidated.
If a comment changes → only @post.comments cache is invalidated.
👉 Caches the HTML output of the article block.
🔹 Low-Level Caching
Use case: When you want to cache arbitrary data — like a set of records, a computed value, or external API results — at the controller or model level.
How it works:
You manually define a cache key and use Rails.cache.fetch to store and retrieve data. If the key is not present in the cache, the block is executed and the result is cached.
Example – Top Posts:
# In controller or service object
def top_posts
Rails.cache.fetch("top_posts", expires_in: 12.hours) do
Post.order(views: :desc).limit(10).to_a
end
end
- This avoids hitting the DB every time users visit the homepage or dashboard.
You can add user-specific or context-specific info to the key:
Rails.cache.fetch(["top_posts", current_user.role], expires_in: 6.hours) do
Post.visible_to(current_user).order(created_at: :desc).limit(10)
end
Rails.cache.fetch("recent_articles", expires_in: 10.minutes) do
Article.order(created_at: :desc).limit(5)
end
👉 Caches query results for 10 minutes.
🔹 HTTP Caching
Use case: When you want to reduce bandwidth and avoid unnecessary re-rendering by allowing browsers or CDNs to use cached versions of your content.
Rails provides built-in helpers like fresh_when and stale? to implement this based on the record’s updated_at timestamp and cache_key.
Example using fresh_when:
def show
@article = Article.find(params[:id])
fresh_when(@article) # Sets ETag and Last-Modified headers
end
If the content hasn’t changed since the last request, Rails will respond with 304 Not Modified, skipping the view rendering.
Example using stale?:
def show
@article = Article.find(params[:id])
if stale?(@article)
render :show
end
end
stale? checks if the content is outdated and only renders if necessary.
Production Cache Store In production, I typically configure a high-performance cache backend:
Redis: Great for both caching and session storage. It supports advanced features like key expiry, namespaces, etc.
Memcached: Lightweight and super-fast, good for ephemeral cache use cases.
Example in config/environments/production.rb:
config.cache_store = :redis_cache_store, { url: ENV['REDIS_URL'] }
Pro Tips: Enable config.action_controller.perform_caching = true in development to test this.
Use tools like rack-mini-profiler or fragment-cacher to inspect which fragments are being hit or missed.
Keep cache blocks small and specific—avoid putting entire pages inside one cache block unless absolutely necessary.
🚀 𝗟𝗲𝘃𝗲𝗹 𝗨𝗽 𝗬𝗼𝘂𝗿 𝗥𝗮𝗶𝗹𝘀 𝗞𝗻𝗼𝘄𝗹𝗲𝗱𝗴𝗲 𝘄𝗶𝘁𝗵 𝗧𝗵𝗲𝘀𝗲 𝗜𝗻𝘁𝗲𝗿𝘃𝗶𝗲𝘄 𝗤𝘂𝗲𝘀𝘁𝗶𝗼𝗻𝘀 🚀
Feature Proc Lambda Arity Check Allows missing arguments (defaults to nil). Strictly enforces the number of arguments. Return Behavior Exits the method immediately. Returns control to the method. Use Case Flexible argument handling, quick inline logic. Function-like behavior with strict argument handling.
Using Proc in Dynamic Method Execution
def perform_action(action)
actions = {
greet: Proc.new { puts "Hello!" },
farewell: Proc.new { puts "Goodbye!" }
}
actions[action].call if actions[action]
end
perform_action(:greet) # Output: "Hello!"
perform_action(:farewell) # Output: "Goodbye!"
Using Lambda for Strict Validations
validate_input = ->(name, age) {
raise "Invalid name" if name.nil? || name.empty?
raise "Invalid age" if age < 18
"Welcome, #{name}!"
}
puts validate_input.call("Alice", 20) # ✅ Output: "Welcome, Alice!"
puts validate_input.call("", 25) # ❌ Raises error "Invalid name"
Feature Proc (Proc.new) Lambda (-> {})
Arity (Arguments Handling) Doesn't enforce argument count (missing args = nil). Strict argument checking (errors if missing).
Return Behavior Exits the calling method immediately. Returns control to the calling method.
Use Case When flexibility is needed. When strict function-like behavior is required.
💡 TL;DR Use Procs when you want loose argument handling and early exit behavior.
Use Lambdas when you want strict function-like execution.
Sharding is a database partitioning technique that distributes data across multiple databases or servers to improve performance, scalability, and availability. Instead of storing all records in a single database, data is split (sharded) into multiple databases based on a specific key (e.g., user ID, region, tenant).
Scalability – Distributes load across multiple database instances.
Performance – Reduces query time by limiting the data each query scans.
Fault Tolerance – Failure in one shard doesn’t affect others.
Multi-tenancy Support – Different customers (tenants) can be stored in separate databases.
Rails 6+ provides built-in support for database sharding using the multiple databases feature (config/database.yml).
Example: User Data Sharded Across Multiple Databases
# config/database.yml
production:
primary:
adapter: postgresql
database: main_db
host: db1.example.com
shard_1:
adapter: postgresql
database: shard1_db
host: db2.example.com
shard_2:
adapter: postgresql
database: shard2_db
host: db3.example.com
Each database (shard_1, shard_2) contains a subset of the total records.
Step 1: Define Database Connections Modify database.yml to add shard configurations.
Step 2: Switch Between Shards in Models Use connects_to in the model:
class User < ApplicationRecord
connects_to database: { writing: :shard_1, reading: :shard_1 }
end
Step 3: Manually Switch Shards in Queries
ActiveRecord::Base.connected_to(role: :writing, shard: :shard_1) do
User.create(name: "Alice")
end
Step 4: Auto-Route Requests Based on Shard Key Example: Shard based on user region.
def set_shard
user_region = params[:region] # Example: "asia"
shard = "shard_#{user_region}"
ActiveRecord::Base.connected_to(role: :writing, shard: shard) do
yield
end
end
This method automatically connects to the appropriate shard.
Use Case Should You Use Sharding? Millions of rows per table ✅ Yes Multi-tenancy (separate databases per customer) ✅ Yes Geo-distributed applications ✅ Yes Simple CRUD apps with low traffic ❌ No Short-term performance issues (use indexing instead) ❌ No
Alternatives to Sharding Read Replicas – Separate read and write databases (primary, replica).
Partitioning – Store different data segments in the same database (PostgreSQL table partitioning).
TL;DR Sharding splits data across multiple databases to improve performance and scalability.
Rails 6+ supports multi-database configurations (connects_to, connected_to).
Use sharding when dealing with high-volume, multi-tenant, or geographically distributed applications.
What is Database Connection Pooling?
Database connection pooling is a technique where a fixed number of database connections are maintained and reused across requests. Instead of opening and closing a connection for each request (which is expensive), Rails maintains a "pool" of open connections to improve performance and reduce overhead.
Rails uses ActiveRecord’s built-in connection pool, which is managed by ActiveRecord::ConnectionAdapters::ConnectionPool. Here's how it works under the hood:
Pool Initialization:
When the app boots, Rails reads the config/database.yml file and initializes a connection pool per environment (and per role/shard if you're using multi-DB).
Per-thread: Checkout Each thread (e.g., Puma worker thread) checks out a connection from the pool when needed. The same thread reuses that connection throughout the request.
Connection Checkout and Check-in:
When a request begins → Rails checks out a connection.
When the request ends → Rails checks it back into the pool.
If all connections are in use, new threads will wait (up to a timeout) for a connection to free up.
Connection Pool Settings (from database.yml)
production:
adapter: postgresql
database: myapp_production
pool: 15 # number of connections
timeout: 5000 # wait time (ms) before raising a timeout error
Common Issues
- Too Small Pool Size
If your app handles many concurrent requests, and your pool size is too low, you’ll see:
ActiveRecord::ConnectionTimeoutError: could not obtain a database connection within 5 seconds
- Too Large Pool Size
Oversizing the pool can exhaust the database's max connections, especially if you scale horizontally.
Summary:
Rails maintains a per-thread connection pool using ActiveRecord.
Connections are checked out at request start and checked in at the end.
You configure the pool size and timeout in database.yml.
Tuning the pool size is critical for performance and stability in production environments.
ActiveRecord callbacks are lifecycle hooks in Rails that allow you to run code before or after certain events on a model — such as create, update, save, or destroy.
They’re used to encapsulate logic that is tightly coupled to a model's data lifecycle.
Common Callbacks:
class Post < ApplicationRecord
before_save :generate_slug
after_create :send_notification
before_destroy :log_deletion
end
eg:
before_validation, after_save, after_create, before_update, before_destroy etc
When to Use Them:
Auto-generating fields (e.g., slugs, tokens)
Logging/auditing changes
Sending notifications or triggering side effects after save
Enforcing business rules closely tied to the model’s lifecycle
When to Avoid Callbacks (Best Practices):
Complex Business Logic:
➤ Move logic into service objects or jobs.
Callbacks can make models "do too much" and harder to test/debug.
What are ActiveSupport::Concerns? ActiveSupport::Concern is a Rails helper module that provides a clean and structured way to write reusable code (usually shared logic) and include it into models, controllers, or other classes.
It builds on Ruby’s native Module but adds a few Rails-specific conveniences for:
Organizing code more cleanly
Hooking into lifecycle methods (included, class_methods)
Avoiding tricky included do blocks and meta-programming
Basic Structure of a Concern
module Archivable
extend ActiveSupport::Concern
included do
scope :archived, -> { where(archived: true) }
end
def archive!
update(archived: true)
end
module ClassMethods
def recently_archived
where("archived_at >= ?", 1.week.ago)
end
end
end
How It Differs From a Plain Ruby Module:
Feature Module ActiveSupport::Concern
Basic inclusion ✅ Yes ✅ Yes
Clean included do syntax ❌ No ✅ Yes
Handles ClassMethods automatically ❌ No ✅ Yes
Designed for Rails (scopes, callbacks) ❌ No ✅ Yes
Explicit load order safety ❌ Risk of bugs ✅ Prevents common issues
Example Use Case: Archivable Records
Imagine you have multiple models (like Post, Comment, Document) that need to support archiving — a common behavior with archived: true/false.
We’ll extract this logic into a reusable concern called Archivable.
Step 1: Create the Concern
# app/models/concerns/archivable.rb
module Archivable
extend ActiveSupport::Concern
included do
scope :archived, -> { where(archived: true) }
scope :unarchived, -> { where(archived: false) }
end
def archive!
update(archived: true)
end
def unarchive!
update(archived: false)
end
def archived?
archived
end
end
Step 2: Include it in your model
# app/models/post.rb
class Post < ApplicationRecord
include Archivable
# other associations, validations, etc.
end
# app/models/comment.rb
class Comment < ApplicationRecord
include Archivable
# other logic
end
Step 3: Use it in Your Application
# Archive a post
post = Post.find(params[:id])
post.archive!
# List only archived posts
Post.archived
# Check if a comment is archived
comment.archived?
# Get all unarchived comments
Comment.unarchived
Both are used to set up many-to-many relationships in Rails, but they differ in flexibility and use case.
has_and_belongs_to_many (HABTM):
Direct many-to-many association with no intermediate model.
Uses a join table (e.g., students_courses) without a corresponding model.
# app/models/student.rb
class Student < ApplicationRecord
has_and_belongs_to_many :courses
end
# app/models/course.rb
class Course < ApplicationRecord
has_and_belongs_to_many :students
end
Requires a join table migration:
create_join_table :students, :courses
Limitations:
Cannot store additional data (e.g., enrollment date, grade) on the relationship.
Less flexible for validations and callbacks.
has_many :through Uses an intermediate model to manage the relationship.
Ideal when you need to store extra data or add logic to the join.
# app/models/student.rb
class Student < ApplicationRecord
has_many :enrollments
has_many :courses, through: :enrollments
end
# app/models/enrollment.rb
class Enrollment < ApplicationRecord
belongs_to :student
belongs_to :course
# extra fields: enrolled_at, grade, etc.
end
# app/models/course.rb
class Course < ApplicationRecord
has_many :enrollments
has_many :students, through: :enrollments
end
Advantages:
More powerful and flexible
Allows custom validations, callbacks, and extra attributes on the join model
Summary:
Feature has_and_belongs_to_many has_many :through
Join Table Yes (no model) Yes (with model)
Extra Attributes ❌ Not possible ✅ Yes
Validations/Callbacks ❌ No ✅ Yes
Preferred for Simple joins Complex logic, extra fields
These are both one-to-one associations but from opposite directions:
belongs_to
Declares ownership from the child side.
The table has the foreign key column.
Used when the current model "belongs to" another.
class Order < ApplicationRecord
belongs_to :user # foreign key: user_id
end
has_one:
Declares ownership from the parent side.
Points to a related record that exists only once.
Often used when you want to access a related model from the owning model.
class User < ApplicationRecord
has_one :profile
end
✅ Summary:
Feature belongs_to has_one
Owns the FK ✅ Yes ❌ No
Declares on Child model Parent model
Association direction Inward Outward
Example Order → belongs_to :user User → has_one :profile
What are different ways to manage configurations in Rails (secrets.yml, credentials.yml.enc, ENV variables)?
Rails provides several ways to manage sensitive data and environment-specific settings like API keys, database credentials, and secret tokens.
- secrets.yml (Rails < 5.2) Located in config/secrets.yml
Used for storing application secrets per environment.
Loaded via Rails.application.secrets[:your_key]
Example:
production:
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
stripe_secret: <%= ENV["STRIPE_SECRET"] %>
Deprecated in favor of credentials.yml.enc in Rails 5.2+
- credentials.yml.enc (Rails 5.2+) Encrypted file managed by Rails for storing secrets.
Decrypted using the master key (config/master.key) or ENV["RAILS_MASTER_KEY"].
Location:
config/credentials.yml.enc
Decrypted with: rails credentials:edit
Example:
aws:
access_key_id: 123
secret_access_key: 456
stripe:
secret_key: sk_test_123
Access:
Rails.application.credentials.aws[:access_key_id]
Rails.application.credentials[:stripe][:secret_key]
Recommended for most applications unless using multi-environment credentials (see below).
Use Case Recommended Approach
Small to medium app with default secrets credentials.yml.enc
Separate dev, staging, and prod credentials Multi-env credentials
Secrets managed externally (Heroku, AWS, Docker) ENV variables
Legacy apps (Rails < 5.2) secrets.yml (legacy only)
What is the difference between dependent: :destroy, dependent: :delete_all, and dependent: :nullify?
How It Works (Conceptually)
Ruby’s GC follows a "mark-and-sweep" algorithm, with enhancements in newer versions:
Mark Phase
Ruby walks through all "reachable" objects — starting from root references (like global variables, method stacks, etc.).
Marks them as "in use."
Sweep Phase
All objects that weren’t marked are considered unused and are freed from memory.
These are part of Ruby’s dynamic method handling. They allow objects to respond to method calls even if those methods are not explicitly defined — a key part of Ruby's metaprogramming capabilities.
method_missing:
A special method you can override to intercept calls to undefined methods.
Commonly used in dynamic proxies, DSLs, or delegators.
respond_to_missing?
Used in combination with method_missing to make respond_to? return true for dynamically handled methods.
Helps tools like irb, introspection, and method lookup work correctly.
In Ruby, an object’s type doesn’t matter — what matters is whether it responds to the methods you need.
def make_sound(animal)
animal.sound
end
class Dog
def sound
"Bark"
end
end
class Cat
def sound
"Meow"
end
end
make_sound(Dog.new) # => "Bark"
make_sound(Cat.new) # => "Meow"
make_sound doesn’t care whether the object is a Dog or Cat, as long as it responds to #sound.
Benefits of Duck Typing:
Flexible: No strict interfaces required
Clean code: Less boilerplate
Powerful metaprogramming
public (default):
Methods are accessible from anywhere — inside or outside the class.
All instance methods are public by default unless specified otherwise.
private:
Can only be called within the context of self, and without an explicit receiver.
Typically used for internal logic that shouldn’t be accessed externally.
protected: Can be called within the same class or its subclasses, even with an explicit receiver — but only if the receiver is an instance of the same class.
Summary:
Modifier Access From Explicit Receiver Allowed? Use Case
public Anywhere ✅ Yes Normal API methods
private Within class ❌ No Internal helpers
protected Same class/subclass ✅ Yes (if same class) Comparisons, shared logic
Summary:
Variable Type Prefix Scope Shared? Usage
Instance Variable @ Per object ❌ No Object state
Class Variable @@ Shared in class & subclasses ✅ Yes Global class-level count, config
Global Variable $ Everywhere in program ✅ Yes (global) Avoid unless absolutely necessary
super:
Passes all arguments that were passed to the current method to the superclass method automatically.
If the superclass method accepts those arguments, it works as expected.
class Parent
def greet(name)
"Hello, #{name}"
end
end
class Child < Parent
def greet(name)
super # passes `name` automatically
end
end
Child.new.greet("Alice") # => "Hello, Alice"
super():
Passes no arguments at all to the superclass method.
Use this when the superclass method does not expect arguments, or when you want to override without forwarding arguments.
class Parent
def greet
"Hello!"
end
end
class Child < Parent
def greet(name)
super() + " I'm #{name}."
end
end
Child.new.greet("Alice") # => "Hello! I'm Alice."
def weird
begin
raise "Oops"
rescue
return "rescued"
ensure
return "ensured"
end
end
puts weird # => ???
Answer: "ensured" — ensure always runs last and overrides the return.
How would you implement your own version of each, map, or select without using Ruby's built-in methods?
What are some metaprogramming techniques in Ruby? Show an example using define_method or method_missing.
1. How do you handle exceptions and errors in Rails? What strategies do you use for logging and notification?
2. How do you approach database modeling in Rails? What considerations do you take for efficient data retrieval and storage?
3. How do you use Rails migrations to manage database schema changes? What are some best practices for writing migrations?
4. What caching mechanisms does Rails offer (fragment, action, and page caching), and when would you use each?
5. How do you design RESTful APIs in Rails? What considerations do you take for API versioning and security?
6. How do you use service objects to encapsulate business logic in Rails? What benefits do they offer?
7. How do you define nested routes in Rails? What are some advanced routing techniques such as shallow routes?
8. Explain polymorphic associations in Rails. When would you choose them over standard associations?
9. How do you tackle the N+1 query problem in Rails? What tools or techniques do you use to optimize queries?
10. How do you handle database transactions in Rails? What steps do you take to optimize database performance through indexing and query tuning?
11. How would you manage caching in a high-traffic, distributed Rails environment? Discuss the use of fragment, action, and page caching.
12. Discuss Rails’ built-in security features. How do you mitigate risks like CSRF, XSS, and SQL injection?
13. How do you design, secure, and version API endpoints in Rails? What are your thoughts on REST vs. GraphQL?
14. What architectural patterns have you implemented to ensure a Rails application scales? Discuss multi-tenancy or micro-services if applicable.
15. How do you address concurrency in Rails? Have you encountered and solved challenges with multi-threading?
16. What is sharding, and how can it be implemented in Rails to optimise data access for large datasets?
17. What testing frameworks and strategies (unit, integration, performance) do you rely on in Rails? How do you ensure comprehensive test coverage?
18. Describe your experience implementing real-time features using Action Cable. What challenges did you encounter?
19. How do you approach refactoring a large, legacy Rails codebase without causing disruptions? What tools or methodologies do you use?
20. Have you worked with Rails 6/7 features such as ActionMailbox, ActionText, or Hotwire? How have they influenced your development process?
21. How do you use service objects or decorators to encapsulate business logic? Share your experiences with Ruby’s meta-programming capabilities.
23. How do you analyze and optimize database queries in Rails? What tools do you use to identify performance bottlenecks?
What are different ways to manage configurations in Rails (secrets.yml, credentials.yml.enc, ENV variables)?
What is the difference between dependent: :destroy, dependent: :delete_all, and dependent: :nullify?
Challenge: Write a class CurrencyConverter that dynamically defines methods like to_usd, to_eur, to_gbp, and converts from a base amount in cents (as integer) to those currencies using given exchange rates.
Challenge: Write a method lazy_primes(n) that lazily generates the first n prime numbers using Ruby's enumerators.
Challenge: Create a counter that increments safely from multiple threads (simulate 100 threads incrementing a shared counter 1000 times each). Use a mutex to avoid race conditions.
Use rescue_from in controllers to handle specific exceptions:
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, with: :not_found
rescue_from StandardError, with: :handle_error
private
def not_found
render json: { error: "Record not found" }, status: :not_found
end
def handle_error(exception)
Rails.logger.error(exception.message)
render json: { error: "Something went wrong" }, status: :internal_server_error
end
end
Use Rollbar, Sentry, or Bugsnag for error notifications.
Normalize data when needed (e.g., extract a tags table if storing repeated text). Use indexes for faster lookups (add_index :users, :email, unique: true). Optimize eager loading to avoid N+1 queries.
Keep migrations idempotent (avoid destructive changes in production).
Use change method over up and down unless a complex rollback is needed. Example:
class AddIndexToUsers < ActiveRecord::Migration[7.0]
def change
add_index :users, :email, unique: true
end
end
Page Caching: Stores full HTML response (caches_page :index).
Action Caching: Caches entire actions but checks authentication.
Fragment Caching: Caches parts of a view:
<% cache @user do %>
<%= render @user.profile %>
<% end %>
SQL Query Caching: Enabled by default in Rails.
Versioning: /api/v1/users Security Considerations: Use JWT or OAuth2 for authentication.
Add rate limiting with rack-attack.
Service objects keep controllers clean:
class UserCreator
def initialize(user_params)
@user_params = user_params
end
def call
User.create(@user_params)
end
end
Benefits: Reusable, testable, and scalable.
resources :authors do
resources :books, only: [:index, :show]
end
Use shallow routes to avoid deep nesting:
resources :books, shallow: true do
resources :reviews
end
- Polymorphic Associations Use when a model can belong to multiple models:
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
Example:
class Post < ApplicationRecord
has_many :comments, as: :commentable
end
class Video < ApplicationRecord
has_many :comments, as: :commentable
end
Use includes or preload:
Post.includes(:comments).each do |post|
puts post.comments.count
end
Use bullet gem to detect N+1.
- Database Transactions & Performance Wrap operations in transactions:
User.transaction do
user.update!(balance: user.balance - 100)
Payment.create!(user: user, amount: 100)
end
Indexing:
add_index :orders, :user_id
Use Redis as a caching layer.
Use low-level caching with Rails.cache.fetch.
CSRF Protection: protect_from_forgery with: :exception
XSS Protection: Use sanitize for user input.
SQL Injection Prevention: Always use ActiveRecord’s query methods:
User.where("email = ?", params[:email]) 13. REST vs. GraphQL REST: Good for simple CRUD APIs.
GraphQL: Good for complex frontends needing flexible data fetching.
Use read replicas and database sharding.
Move long tasks to background jobs.
Use Redis locks to prevent race conditions.
Use octopus gem or Rails 6 multiple databases feature.
Unit tests: RSpec or Minitest
Integration tests: Capybara
Performance testing: Benchmark
class ChatChannel < ApplicationCable::Channel
def subscribed
stream_from "chat_#{params[:room]}"
end
end
Challenges: Scaling with Redis, handling connections.
Use rubocop for code consistency.
Gradually introduce service objects.
Hotwire (Turbo & Stimulus)
ActionText (Rich Text ing)
ActionMailbox (Incoming Emails Handling)
Rack is a lightweight interface between web servers and Ruby frameworks.
Custom Middleware:
class LoggerMiddleware
def initialize(app)
@app = app
end
def call(env)
Rails.logger.info "Request received: #{env['PATH_INFO']}"
@app.call(env)
end
end
Solved using includes, preload, or eager_load.
Use concerns for shared logic:
module Taggable
extend ActiveSupport::Concern
included do
has_many :tags
end
end
HABTM: Direct many-to-many without extra fields.
HMT: Uses a join model for additional attributes.
class User
@@class_var = "class var"
@instance_var = "instance var"
end
Strings are mutable, Numbers & Booleans are immutable.
Ruby uses Mark-and-Sweep Garbage Collection.
include adds instance methods.
extend adds class methods.
Threads: Pre-emptive (run in parallel).
Fibers: Cooperative (manual yielding).
Lambdas check arity (number of arguments), Procs don’t.
params.require(:user).permit(:name, :email) CSRF Protection:
protect_from_forgery with: :exception ActiveRecord Callbacks: before_save, after_commit, etc.
Convention Over Configuration: Rails’ opinionated design.
Difference Between save and save!: save! raises an exception on failure.
Want Mock Interview Practice? 🔥 I can generate Rails coding challenges or mock system design questions! 🚀
📌 Associations in Rails and How They Are Formed Associations in Rails define relationships between models, allowing efficient data retrieval and manipulation.
- belongs_to Association
One-to-One or Many-to-One relationship
The child model holds the foreign key.
Example: A Book belongs to an Author
class Book < ApplicationRecord
belongs_to :author
end
class Author < ApplicationRecord
has_many :books
end
The books table must have an author_id column.
Foreign key: author_id in books.
class AddAuthorToBooks < ActiveRecord::Migration[7.0]
def change
add_reference :books, :author, foreign_key: true
end
end
One-to-One relationship
The parent model has one associated record.
Example: A User has one Profile
class User < ApplicationRecord
has_one :profile
end
class Profile < ApplicationRecord
belongs_to :user
end
Foreign key: user_id in profiles.
class AddUserToProfiles < ActiveRecord::Migration[7.0]
def change
add_reference :profiles, :user, foreign_key: true
end
end
One-to-Many relationship
A record has many related records.
Example: An Author has many Books
class Author < ApplicationRecord
has_many :books
end
class Book < ApplicationRecord
belongs_to :author
end
Foreign key: author_id in books.
Many-to-Many relationship with a join table containing additional attributes.
Example: Doctor has many Patients through Appointments
class Doctor < ApplicationRecord
has_many :appointments
has_many :patients, through: :appointments
end
class Patient < ApplicationRecord
has_many :appointments
has_many :doctors, through: :appointments
end
class Appointment < ApplicationRecord
belongs_to :doctor
belongs_to :patient
end
Join table: appointments (with doctor_id and patient_id).
class CreateAppointments < ActiveRecord::Migration[7.0]
def change
create_table :appointments do |t|
t.references :doctor, foreign_key: true
t.references :patient, foreign_key: true
t.datetime :appointment_date
t.timestamps
end
end
end
Direct Many-to-Many relationship without additional attributes.
Example: Students and Courses
class Student < ApplicationRecord
has_and_belongs_to_many :courses
end
class Course < ApplicationRecord
has_and_belongs_to_many :students
end
Requires a join table (courses_students) with no extra columns.
class CreateCoursesStudentsJoinTable < ActiveRecord::Migration[7.0]
def change
create_join_table :courses, :students do |t|
t.index :course_id
t.index :student_id
end
end
end
📝 HABTM vs. has_many :through
Use has_many :through if the join table needs extra columns (e.g., appointments.date).
Use HABTM if the join table is purely relational.
A model can belong to multiple other models using a single association.
Example: A Comment can belong to both Post and Video
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
class Post < ApplicationRecord
has_many :comments, as: :commentable
end
class Video < ApplicationRecord
has_many :comments, as: :commentable
end
The comments table has:
commentable_type (stores "Post" or "Video")
commentable_id (stores the related record’s ID)
class CreateComments < ActiveRecord::Migration[7.0]
def change
create_table :comments do |t|
t.text :body
t.references :commentable, polymorphic: true, index: true
t.timestamps
end
end
end
A model associates with itself.
Example: Employees reporting to a Manager
class Employee < ApplicationRecord
belongs_to :manager, class_name: "Employee", optional: true
has_many :subordinates, class_name: "Employee", foreign_key: "manager_id"
end
Foreign key: manager_id in employees.
class AddManagerToEmployees < ActiveRecord::Migration[7.0]
def change
add_reference :employees, :manager, foreign_key: { to_table: :employees }
end
end
Association Type Description Example
belongs_to Child model holds foreign key Book belongs_to Author
has_one One-to-one User has_one Profile
has_many One-to-many Author has_many Books
has_many :through Many-to-many with join model Doctor has_many Patients through Appointments
has_and_belongs_to_many (HABTM) Many-to-many without extra fields Students and Courses
polymorphic Model belongs to multiple types Comment belongs_to Post or Video
self-join Model relates to itself Employee belongs_to Manager