Ruby On Rails Models
π Ruby on Rails Part 1: Mastering the Model in MVC - Tips, Hacks & Major Libraries π―
Welcome to the first part of the Ruby on Rails MVC (Model-View-Controller) series! In this post, weβre diving deep into the Modelβthe backbone of your Rails app. Models are where your data lives and the place to define business logic. Letβs explore some of the best tips, hacks, and essential libraries to supercharge your Models and make your Rails app stand out! π‘
π§ What is a Model in MVC?
In the Rails MVC architecture, the Model is responsible for handling data and business logic. It communicates with the database, defines relationships, and keeps your appβs logic clean and well-organized. A Model corresponds to a database table, and each instance of the Model represents a row in that table.
π οΈ Top Tips for Working with Models in Rails
1. Keep Models Skinny, Logic Elsewhere π
A common Rails best practice is βskinny modelsββkeep your model classes as simple as possible. Offload complex logic to service objects, concerns, or even custom validators.
π Example:
# Instead of doing this:
class User < ApplicationRecord
def premium_user?
# complex logic here
end
end
# Create a service:
class UserService
def initialize(user)
@user = user
end
def premium_user?
# complex logic here
end
end
Hack: For frequently used logic like validations, use ActiveSupport Concerns to keep your models organized! β¨
2. Use scopes
for Reusable Queries π
Avoid cluttering your model with complex query methods. Use scopes
to create reusable, chainable queries.
π Example:
class Article < ApplicationRecord
scope :published, -> { where(published: true) }
scope :recent, -> { order(created_at: :desc) }
end
# Usage
Article.published.recent
3. Optimize with includes
for Eager Loading ποΈ
To avoid N+1 query problems, always use includes
to preload associations and reduce database hits.
π Example:
# N+1 problem:
@posts = Post.all
@posts.each do |post|
post.comments.each do |comment|
puts comment.body
end
end
# Solution: Eager load comments
@posts = Post.includes(:comments)
@posts.each do |post|
post.comments.each do |comment|
puts comment.body
end
end
π Must-Know Gems and Libraries for Models
1. Pundit - For Authorization π
Authorization is an important part of app security, and Pundit is a simple, scalable way to manage permissions in your models.
π Usage Example:
# app/policies/article_policy.rb
class ArticlePolicy
attr_reader :user, :article
def initialize(user, article)
@user = user
@article = article
end
def update?
user.admin? || article.author == user
end
end
With Pundit, you can easily enforce role-based authorization across your Models!
2. PaperTrail - Versioning Models β³
Ever needed to track changes made to your records? PaperTrail is a fantastic gem that enables versioning, so you can see the history of your data.
π Usage Example:
class Post < ApplicationRecord
has_paper_trail
end
# Get versions of a post
post = Post.find(1)
post.versions # Returns all versions of the post
This is incredibly helpful for building features like an activity log or undo functionality.
3. Annotate - Never Forget Your Schema Again π
Annotate adds schema information as comments at the top of your models. This is useful for quickly seeing a modelβs attributes without running migrations or checking the schema.
π Installation:
gem install annotate
annotate
With just one command, your models are automatically documented with all the relevant fields and associations!
4. Draper - Decorators for Clean Views π
Use Draper to wrap your models in decorators, keeping view logic out of your models and views. Decorators allow you to add view-related methods to models without cluttering them.
π Example:
class PostDecorator < Draper::Decorator
delegate_all
def formatted_date
object.created_at.strftime("%B %d, %Y")
end
end
# Usage in views
<%= @post.decorate.formatted_date %>
This helps keep both your Models and Views clean and focused on their respective jobs.
β‘ Hacks to Level Up Your Rails Models
1. Use Callbacks Wisely β‘
Callbacks like before_save
and after_commit
are powerful, but overusing them can lead to hard-to-debug issues. Instead, limit callbacks to truly necessary operations and consider moving complex logic to service objects.
π Good use case:
class User < ApplicationRecord
before_save :downcase_email
private
def downcase_email
self.email = email.downcase
end
end
2. Leverage ActiveModel::Validations
for Custom Validations β
If your model has complex validation logic, use ActiveModel::Validations
to create custom validators.
π Example:
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/
record.errors.add(attribute, 'is not a valid email')
end
end
end
class User < ApplicationRecord
validates :email, presence: true, email: true
end
3. Use find_each
for Large Datasets π§
When working with a large number of records, avoid loading everything into memory at once. Instead, use find_each
to batch process records.
π Example:
# Instead of this:
User.all.each do |user|
# send email
end
# Use find_each for batches:
User.find_each(batch_size: 100) do |user|
# send email
end
π Wrapping Up
The Model is the core of your Rails app, and by applying these tips, hacks, and gems, you can make it much more efficient, clean, and easy to maintain. From keeping your models skinny and efficient to leveraging powerful libraries like Pundit and PaperTrail, you now have the tools to take your Rails Models to the next level! πͺ
Stay tuned for Part 2, where weβll explore the View and how to create user-friendly, efficient frontends in Rails! π
Until next time, happy coding! π»β¨
What do you think of these Model tips and hacks? Let me know in the comments below! π
© Lakhveer Singh Rajput - Blogs. All Rights Reserved.