Ruby On Rails Hacks And Tricks
Ruby on Rails Unique Hacks and Tricks Everyone Should Know π
Ruby on Rails (RoR) is known for its ease of use and powerful features, but there are plenty of hidden tricks and hacks that can make your Rails development even smoother. In this blog, weβll explore some unique Rails tips and techniques to help you write more efficient, maintainable, and clean code. Letβs dive in! π
1. Efficient Batch Processing with find_each
π¦
When working with large datasets, loading everything at once can be inefficient. Use find_each
to process records in batches, reducing memory usage and improving performance.
User.find_each(batch_size: 1000) do |user|
# Process each user
end
2. Retrieve Specific Attributes with pluck
π§
To fetch only the necessary attributes from the database, use pluck
to avoid loading full ActiveRecord objects.
user_ids = User.pluck(:id)
This method directly queries the specified columns, which is faster and more memory-efficient.
3. Create Reusable Queries with scope
π
Scopes are a great way to encapsulate common queries and keep your code clean and readable.
class Post < ApplicationRecord
scope :published, -> { where(published: true) }
scope :recent, -> { order(created_at: :desc) }
end
# Usage
Post.published.recent
4. Manage States with enum
ποΈ
Enums provide a way to map integer values to human-readable strings, simplifying state management.
class Order < ApplicationRecord
enum status: { pending: 0, processing: 1, shipped: 2, delivered: 3 }
end
# Usage
order = Order.new(status: :pending)
order.pending? # true
5. Encapsulate Complex Validations with Custom Validators π οΈ
Custom validators let you encapsulate complex validation logic, making your models cleaner and more maintainable.
class CustomValidator < ActiveModel::Validator
def validate(record)
unless record.attribute.present?
record.errors.add(:attribute, "can't be blank")
end
end
end
class User < ApplicationRecord
validates_with CustomValidator
end
6. Optimize Test Suites with let
and before
Blocks β‘
Use let
and before
blocks in RSpec to organize and speed up your tests, reducing duplication and improving readability.
RSpec.describe User, type: :model do
let(:user) { User.create(name: "Test User") }
before do
# Setup code
end
it "has a valid factory" do
expect(user).to be_valid
end
end
7. Modularize Code with ActiveSupport::Concern
π¦
ActiveSupport::Concern
allows you to create reusable modules for your models or controllers, promoting clean and modular code.
module Trackable
extend ActiveSupport::Concern
included do
before_action :track_activity
end
def track_activity
# Tracking code
end
end
class ApplicationController < ActionController::Base
include Trackable
end
8. Simplify Associations with delegate
ποΈ
The delegate
method can streamline your code by delegating method calls to associated objects.
class User < ApplicationRecord
has_one :profile
delegate :bio, to: :profile
end
# Usage
user.bio
9. Use after_commit
for Post-Transaction Logic π·οΈ
The after_commit
callback ensures that code runs only after a transaction has been successfully committed, which is useful for background jobs or external notifications.
class Order < ApplicationRecord
after_commit :notify_customer
def notify_customer
# Code to send notification
end
end
10. Batch Processing with find_in_batches
π
Similar to find_each
, find_in_batches
processes records in batches but gives you more control over batch processing.
User.find_in_batches(batch_size: 1000) do |batch|
batch.each do |user|
# Process each user
end
end
11. Use ActiveSupport::Notifications
for Custom Event Handling π£
Rails provides a powerful mechanism for subscribing to and broadcasting events using ActiveSupport::Notifications
. This can be useful for logging, monitoring, or custom event handling.
ActiveSupport::Notifications.subscribe('user.created') do |name, start, finish, id, payload|
puts "User created: #{payload[:user].inspect}"
end
# Triggering the event
ActiveSupport::Notifications.instrument('user.created', user: @user)
12. Use fetch_or_initialize_by
for Safe Object Creation π οΈ
fetch_or_initialize_by
allows you to find or initialize an object based on given attributes, ensuring itβs not unnecessarily saved until you explicitly call save
.
user = User.fetch_or_initialize_by(email: 'example@example.com') do |user|
user.name = 'New User'
end
13. Optimize Queries with includes
for Eager Loading π
When querying associated records, use includes
to avoid the N+1 query problem by eager loading associations.
# Avoid N+1 queries
posts = Post.includes(:comments).where(published: true)
posts.each do |post|
post.comments.each do |comment|
# Process comment
end
end
Conclusion
Ruby on Rails is packed with powerful features and tricks that can significantly enhance your development process. By applying these unique hacks and techniques, you can write more efficient, maintainable, and clean code. Keep exploring Rails to discover even more ways to streamline your workflow and improve your applications. Happy coding! π
© Lakhveer Singh Rajput - Blogs. All Rights Reserved.