

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. 😉
