Ruby on Rails Interview Questions and Answers — Model — Part 2

Gokul
9 min readSep 24, 2023

--

  • Describe the significance of migrations in Rails models and provide an example of creating one.
  • What is the difference between `belongs_to` and `has_many` associations in Rails models?
  • Can you explain the use of callbacks in Rails models, and when might you use them?
  • How do you query the database to retrieve records that meet specific criteria in Rails?
  • What is the purpose of the `find` and `find_by` methods in Rails models?

6. Describe the significance of migrations in Rails models and provide an example of creating one

Migrations in Ruby on Rails are a crucial aspect of managing and evolving the database schema over time. They allow you to version control and automate changes to the database structure, making it easier to develop and maintain your application as it grows. Migrations help you keep track of changes like creating or modifying tables, adding or removing columns, and defining indexes or constraints.

Here’s the significance of migrations in Rails models:

Version Control for Database Schema: Migrations provide a structured way to version-control your database schema changes alongside your application code. Each migration represents a discrete change to the schema, making it easy to roll back changes or apply them to a different environment.

Database Portability: Migrations are database-agnostic, meaning you can use the same set of migration files to manage your database schema across different database management systems (DBMSs) like PostgreSQL, MySQL, or SQLite. Rails takes care of generating the appropriate SQL for your chosen DBMS.

Collaboration: When working on a project with a team, migrations ensure that every developer can apply the same changes to their local databases. This consistency is essential for collaboration and testing.

Testing and Staging Environments: Migrations make it simple to set up and tear down databases for testing and staging environments. You can easily re-create the schema and populate it with test data.

Database Evolution: As your application evolves, you can use migrations to add new features, modify existing data structures, or optimize database performance without losing existing data.

Suppose you want to create a new table called “posts” with columns for the title and content of each post. You can create a migration for this purpose:

rails generate migration CreatePosts

This command generates a new migration file in the db/migrate directory. The filename will include a timestamp to ensure it runs in the correct order.

Open the generated migration file, and you’ll see something like this:

# db/migrate/[timestamp]_create_posts.rb

class CreatePosts < ActiveRecord::Migration[6.1]
def change
create_table :posts do |t|
t.string :title
t.text :content

t.timestamps
end
end
end

In this migration file:

  • CreatePosts is the name of the migration class, following the convention of "Create[TableName]".
  • Inside the change method, create_table is used to define the "posts" table with two columns: "title" and "content." The t.timestamps line adds timestamp columns for "created_at" and "updated_at," which are commonly used for recording when a record was created or last updated.

After defining the migration, you can apply it to your database using the following command:

rails db:migrate

This will execute the migration, creating the “posts” table in your database. You can then use your model to interact with this table, and Rails will handle the database operations behind the scenes.

7. What is the difference between `belongs_to` and `has_many` associations in Rails models?

Cardinality

  • belongs_to: This association represents a one-to-one or many-to-one relationship. It is used when one record in the model "belongs to" another record in a different model. For example, a "Comment" may belong to a single "Post," implying that multiple comments can be associated with the same post.
  • has_many: This association represents a one-to-many or many-to-many relationship. It is used when one record in the model can be associated with multiple records in another model. For example, a "Post" can have many "Comments," indicating that a post can have multiple comments associated with it.

Direction

  • belongs_to: This association is typically used on the model that has a foreign key column referencing another model's primary key. It establishes the relationship from the perspective of the model with the foreign key. For example, if a "Comment" model has a foreign key column called "post_id," you would use belongs_to to associate it with the "Post" model.
  • has_many: This association is used on the model that doesn't contain the foreign key column but is related to the model with the foreign key. It defines the relationship from the perspective of the model that doesn't have the foreign key. For example, if the "Comment" model has a belongs_to association with "Post," the "Post" model would have a has_many association with "Comment."

Method Names

  • belongs_to: When you use belongs_to, Rails automatically generates methods that allow you to access the associated object using the singular name of the associated model. For example, if you have belongs_to :post, you can access the associated post using comment.post.
  • has_many: When you use has_many, Rails generates methods that allow you to access the associated objects using the pluralized name of the associated model. For example, if you have has_many :comments, you can access the associated comments using post.comments.

Database Schema

  • belongs_to: The model with a belongs_to association typically contains the foreign key column in its database table. This foreign key establishes the relationship to the other model.
  • has_many: The model with a has_many association doesn't contain the foreign key column but references the other model through the foreign key. The foreign key is in the table of the model that belongs_to the other.
# Post model
class Post < ApplicationRecord
has_many :comments
end

# Comment model
class Comment < ApplicationRecord
belongs_to :post
end

In this example:

  • A “Post” can have many “Comments” (one-to-many relationship).
  • A “Comment” belongs to a single “Post.”
  • The “Comment” model has a foreign key column called “post_id” that references the “Post” model’s primary key.

8. Can you explain the use of callbacks in Rails models, and when might you use them?

Callbacks in Ruby on Rails models are methods that are automatically triggered at specific points in the lifecycle of an ActiveRecord object. These callbacks allow you to inject custom logic before or after certain events, such as record creation, updating, or deletion. Callbacks are useful for performing actions related to data manipulation, validation, and other business logic in a systematic and organized manner.

Rails provides a variety of callbacks that can be used in your models. Here are some common ones:

  1. before_validation and after_validation: These callbacks are triggered before and after the validation process. You can use them to perform data preprocessing, formatting, or additional validation checks.
  2. before_save and after_save: These callbacks are triggered before and after the record is saved to the database. They are commonly used for tasks like updating timestamps or performing actions that need to occur whenever the record is saved.
  3. before_create and after_create: These callbacks are specific to record creation and are triggered before and after a new record is inserted into the database.
  4. before_update and after_update: These callbacks are specific to record updates and are triggered before and after an existing record is modified in the database.
  5. before_destroy and after_destroy: These callbacks are triggered before and after a record is deleted from the database. You can use them for tasks like cleaning up associated records or performing logging.
class User < ApplicationRecord
before_save :normalize_email
after_create :send_welcome_email

private

def normalize_email
self.email = email.downcase.strip
end

def send_welcome_email
# Code to send a welcome email to the user
end
end
  • The before_save callback triggers the normalize_email method, which modifies the email address by downcasing it and removing leading/trailing whitespace before the user record is saved to the database.
  • The after_create callback triggers the send_welcome_email method, which sends a welcome email to the user after their record has been successfully created in the database.

Here are some scenarios where you might use callbacks in Rails models,

Data Formatting: You can use callbacks to ensure that data is formatted consistently before saving it to the database. For example, normalizing email addresses or phone numbers.

Timestamps: You can automatically update timestamp fields like created_at and updated_at using before_save and before_create callbacks.

Authorization and Authentication: You can implement custom authorization or authentication checks before saving or deleting records.

Sending Notifications: You can trigger email notifications or other alerts after specific events, such as user registration or order placement.

Complex Validations: In some cases, you may need to perform complex validation checks that involve multiple attributes or external services. Callbacks can help encapsulate this logic.

Logging and Auditing: You can use callbacks to log changes to records or maintain an audit trail of actions taken on records.

9. How do you query the database to retrieve records that meet specific criteria in Rails?

Using the where method

The where method allows you to specify conditions to filter records based on column values. You can chain multiple where clauses together to create more complex queries.

# Retrieve all users with the name "John"
users = User.where(name: "John")

# Retrieve users with both the name "John" and age 30
users = User.where(name: "John").where(age: 30)

# Retrieve users with names "John" or "Jane"
users = User.where(name: ["John", "Jane"])

Using the find and find_by methods

The find method allows you to retrieve a single record by its primary key (ID). The find_by method lets you find a single record by specifying conditions.

# Retrieve a user by ID
user = User.find(1)

# Retrieve a user by email
user = User.find_by(email: "john@example.com")

Using the order Method

The order method is used to specify the order in which records should be retrieved. You can use it to sort records based on one or more columns

# Retrieve users in ascending order of age
users = User.order(:age)

# Retrieve users in descending order of created_at timestamp
users = User.order(created_at: :desc)

Using the limit and offset Methods

You can use the limit method to restrict the number of records returned, and the offset method to skip a certain number of records. These methods are commonly used for pagination

# Retrieve the first 10 users
users = User.limit(10)

# Retrieve the next 10 users (pagination)
users = User.limit(10).offset(10)

Using Advanced Querying

ActiveRecord provides advanced querying capabilities, such as joins and subqueries, for more complex queries. You can use the joins method to combine records from multiple tables and the select method to specify which columns to retrieve.

# Retrieve all posts with their associated authors
posts = Post.joins(:author)

# Retrieve only the titles of published posts
titles = Post.where(published: true).pluck(:title)

Chaining Query Methods

You can chain multiple query methods together to build more sophisticated queries.

# Retrieve the first 5 published posts authored by "John"
posts = Post.where(published: true).joins(:author).where(authors: { name: "John" }).limit(5)

Using Custom SQL Queries

In some cases, you may need to execute custom SQL queries. Rails provides the find_by_sql method for this purpose. However, you should use this method cautiously and prefer ActiveRecord's query methods whenever possible to benefit from database-agnostic code.

users = User.find_by_sql("SELECT * FROM users WHERE age > 30")

10. What is the purpose of the `find` and `find_by` methods in Rails models?

find Method

The find method is used to retrieve a record from the database by its primary key (usually id). Its primary purpose is to fetch a single record based on the provided primary key value. If the record with the specified primary key is not found, it raises an ActiveRecord::RecordNotFound exception.

user = User.find(1) # Fetches the user with ID 1

If no record with ID 1 exists, the ActiveRecord::RecordNotFound exception will be raised.

find_by Method

The find_by method is used to retrieve a single record from the database based on specific attribute values. It allows you to find a record by specifying conditions for one or more attributes. If a record matching the conditions is found, it is returned as an object; otherwise, nil is returned, and no exception is raised.

user = User.find_by(email: "john@example.com") # Fetches the user with the specified email address

If no user with the email “john@example.com” exists, user will be nil.

You can also chain multiple conditions with find_by to retrieve records based on multiple attributes:

user = User.find_by(name: "John", age: 30) # Fetches a user with both the specified name and age

If no user matches both conditions, user will be nil.

The key difference between find and find_by is how they handle missing records. find raises an exception if the record is not found, making it suitable when you expect a specific record to exist and want to handle the absence of the record explicitly. On the other hand, find_by returns nil if the record is not found, making it a more lenient option for querying records where existence is not guaranteed.

Both methods are useful in different scenarios, depending on your application’s requirements and whether you want to gracefully handle missing records or raise an exception when a record is not found.

I appreciate you taking the time to read this. Please follow me on Medium and subscribe to receive access to exclusive content in order to keep in touch and continue the discussion. Happy Reading!!!

--

--

Gokul

Consultant | Freelancer | Ruby on Rails | ReactJS