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.