
Hey fellow developers! Let’s talk about Ruby on Rails, the framework that’s like a Swiss Army knife for web apps—powerful, elegant, but oh boy, it can turn into a hot mess if you don’t respect its “convention over configuration” mantra. Over the years, I’ve seen Rails codebases that spark joy (shoutout to Marie Kondo) and others that look like a toddler’s spaghetti art project. Let’s make sure yours falls into the first category.
Here are Ruby on Rails best practices I’ve learned the hard way—so you don’t have to.
1. Keep Your Controllers Skinny (Like Your Post-Holiday Jeans)
Controllers are meant to coordinate, not do heavy lifting. If your controller action looks like a Tolstoy novel, you’re doing it wrong.
Bad Example:
def create
@user = User.new(user_params)
if @user.save
UserMailer.welcome_email(@user).deliver_now
AnalyticsService.track(@user, "signup")
redirect_to dashboard_path
else
render :new
end
end
This isn’t terrible, but wait until you add 10 more services. Yikes.
Good Example:
def create
@user = UserCreationService.call(user_params)
redirect_to dashboard_path if @user.persisted?
end
Move logic to service objects or model callbacks (wisely!). Your controller stays skinny, and you avoid a mid-life crisis.
2. Embrace ActiveRecord, But Don’t Let It Bite You
ActiveRecord is magical—until it generates N+1 queries that slow your app to a crawl.
Bad Example:
# Loading 100 posts and hitting the database 101 times. Classic N+1!
Post.limit(100).each { |post| puts post.author.name }
Good Example:
# Preload authors in 2 queries. Be a hero, not a villain.
Post.includes(:author).limit(100).each { |post| puts post.author.name }
Use tools like bullet
to catch N+1 issues early. Your database will thank you.
3. Test Like Your Reputation Depends On It (Because It Does)
Rails has RSpec, MiniTest, and factories. Use them. No excuses.
Example:
# Test for a simple service object
describe UserCreationService do
let(:params) { { email: "longpham@codevivu.com", password: "codevivu" } }
it "creates a user and sends a welcome email" do
expect { described_class.call(params) }
.to change(User, :count).by(1)
.and have_enqueued_mail(UserMailer, :welcome_email)
end
end
Tests are your safety net. Without them, you’re coding on a tightrope.
4. Use the Rails Console Like a Wizard’s Spellbook
Stuck debugging? The Rails console is your best friend.
Pro Tip:
# Need to test a complex query?
User.includes(:posts).where(posts: { published: true }).first(10)
# Or simulate a request in the console!
app.get("/users/1")
Just remember: don’t run User.destroy_all
in the production console. I’ve seen things.
5. Security Isn’t Optional (Unless You Like Headlines)
Rails has built-in protections, but stay vigilant.
Always sanitize params:
# Strong parameters FTW
def user_params
params.require(:user).permit(:email, :password)
end
Use has_secure_password
for passwords, and avoid rolling your own auth unless you’re a masochist.
6. Background Jobs for the Win
Don’t make users wait for slow tasks. Use Sidekiq or Active Job.
Example:
# Send emails async
class UserMailer < ApplicationMailer
def welcome_email(user)
mail(to: user.email, subject: "Welcome!")
end
end
# In your service:
UserMailer.welcome_email(@user).deliver_later
Your users get instant feedback, and your app stays responsive.
7. Cache Like You’re Hiding Snacks from Your Kids
Caching saves your app from redundant work.
Fragment Caching Example:
<% cache @user do %>
<%= render @user.posts %>
<% end %>
Use Redis or Memcached for better performance. Just don’t cache stale data—nobody likes moldy snacks.
8. Stay Up to Date
Upgrade Rails and gems regularly. Security patches, performance boosts, and new features await!
Pro Tip:
Use bundle outdated
to find outdated gems.
Final Thoughts: Keep Calm and rails new
Ruby on Rails is a joy when you follow best practices. Keep your code clean, test relentlessly, and remember: every before_action
you write should have a purpose. Now go build something amazing—and maybe share this post with that one coworker who still writes 100-line controller actions. 😉