Ruby
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Methods and Blocks
-
Section 4: Object-Oriented Ruby
-
Section 5: Metaprogramming
-
Section 6: Working with Data and Files
-
Section 7: Ruby Frameworks Overview
-
Section 8: Ecosystem and Testing
-
Section 9: Practical Projects
-
Section 10: Interview Practice
-
Section 11: Data Structures and Algorithms in Ruby
-
Section 12: More Practice Exercises
-
Section 13: Enumerable and Functional Style
-
Section 14: More OOP Practice
-
Section 15: More Testing
-
Section 16: Enumerable and Comparable Modules In Depth
-
Section 17: Ruby Standard Library: Core Utilities
-
Section 18: Ruby Standard Library: Data and Security
-
Section 19: Ruby Standard Library: CLI and Text
-
Section 20: Ruby Networking
-
Section 21: Ruby on Rails Deep Dive
-
Section 22: Ruby Metaprogramming Deep Dive
-
Section 23: Ruby Design Patterns
-
Section 24: Ruby Concurrency
-
Section 25: Ruby Testing Deep Dive
-
Section 26: Ruby Gems and Packaging
-
Section 27: Ruby Performance
-
Section 28: More Practice Exercises
-
Section 29: More Interview Practice
-
Section 30: Rails API Development
-
Section 31: Rails Authentication and Authorization
-
Section 32: Rails Testing Deep Dive
-
Section 33: Rails Performance
-
Section 34: Rails Deployment
-
Section 35: Sinatra and Lightweight Ruby Web Apps
-
Section 36: More Ruby Language Deep Dive
-
Section 37: Ruby 3.x Modern Features
-
Section 38: More Data Structures in Ruby
-
Section 39: More Practical Projects
-
Section 40: Ruby Ecosystem Tools
-
Section 41: More Practice and Review
-
Section 42: Final Practice and Mastery
-
Section 43: Ruby Interview Deep Dive
-
Section 44: Ruby Background Processing Deep Dive
-
Section 45: Ruby GraphQL
-
Section 46: Ruby Object Model Deep Dive
-
Section 47: Ruby Hanami Framework Overview
-
Section 48: Ruby gRPC and Protocol Buffers
-
Section 49: Ruby Data Processing
-
Section 50: Ruby Search Integration
-
Section 51: Ruby File Upload and Media
-
Section 52: Ruby Email and Notifications
-
Section 53: Ruby Admin Panels
-
Section 54: Ruby Feature Flags and Experimentation
-
Section 55: Ruby Monitoring and Observability
-
Section 56: Ruby Docker and Deployment Deep Dive
-
Section 57: Ruby Security Deep Dive
-
Section 58: More Advanced Metaprogramming
-
Section 59: More Final Projects
85: Action Controller Filters
Imagine you're running a high-end members-only club. You've got a DJ inside playing great music—that's your controller action. Now, you could have the DJ stop the music every single time someone walks through the door to check their membership card, ask for their name, and verify their age. But that would be an absolute disaster. The music would never flow, and the DJ would spend more time doing paperwork than playing records.
Instead, you hire a bouncer. The bouncer stands at the door and handles all the "pre-flight" checks. If the guest isn't on the list, the bouncer turns them away before they ever set foot in the club. If they are cleared, the bouncer steps aside and lets them in to enjoy the music. Once the guest leaves, maybe a staff member does a quick sweep of the room to make sure no glasses were broken. That's a post-visit check.
In Rails, Action Controller Filters are your bouncers. They allow you to extract repetitive logic—like authentication, finding a record in the database, or checking permissions—out of your individual actions and into a centralized place.
The Gatekeeper Pattern
The most common filter you'll use is before_action. I've seen way too many beginners manually call current_user or find_post at the start of every single method in their controller. It's tedious and makes your code noisy. Here is how we actually handle that in a professional codebase:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :edit, :update, :destroy]
before_action :ensure_logged_in, only: [:new, :create, :edit, :update, :destroy]
def show
# @post is already set by the filter!
end
def edit
# @post is already set and we know the user is logged in.
end
private
def set_post
@post = Post.find(params[:id])
end
def ensure_logged_in
unless current_user
redirect_to login_path, alert: "You must be logged in to do that."
end
end
end
Notice the only: option. This is vital. You don't want the set_post filter running on the index action, because there is no params[:id] when you're looking at a list of all posts. If you tried that, Rails would throw an error and your app would crash. You can also use except: if it's easier to list the few actions that shouldn't be filtered.
Wrapping Logic with around_action
Sometimes a before_action and an after_action aren't enough because they don't share the same local state. That's where around_action comes in. Think of this as a "wrapper." It's like an escort who walks a guest into the club, stays with them the whole time, and then walks them out.
I typically use these for things like performance timing or database transactions. The key is the yield keyword. If you don't call yield, the actual controller action will never execute—the guest never gets into the club.
class ReportsController < ApplicationController
around_action :track_performance
def heavy_export
# Some complex logic that takes 5 seconds
render plain: "Export Complete"
end
private
def track_performance
start_time = Time.now
yield # This is where the 'heavy_export' action actually runs
end_time = Time.now
Rails.logger.info "Report took #{end_time - start_time} seconds to generate."
end
end
The Order of Operations
One thing that trips people up is the execution order. Filters are run in the order they are defined in the class. If you have three before_action calls, Rails hits them one by one. If any of those filters performs a redirect_to or render, the chain is halted immediately. The subsequent filters and the actual action are skipped entirely. This is exactly why our ensure_logged_in filter works—it stops the "unauthorized" guest right at the door.
📋 Practical Task
Building a Premium Subscription Guard
You are building a blog where some articles are free and some are "Premium." You need to ensure that users cannot access premium articles unless their account has a premium boolean set to true.
Your Task:
- In the
ArticlesController, create abefore_actioncalledverify_premium_access. - This filter should only run on the
showaction. - Inside the filter, find the article by ID. If the article is marked as
premium: trueand thecurrent_useris either not logged in or not a premium member, redirect them to thepricing_pathwith a flash message saying "This content requires a premium subscription." - Ensure the
showaction remains clean, relying on the filter to have already handled the authorization and set the@articleinstance variable.
There are no comments for now.