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
67: Tempfile for Temporary Files
A few years ago, I was reviewing a pull request for a reporting tool that generated large CSV exports. The developer had implemented a simple logic: create a file called export.csv in a /tmp folder, write the data, and then upload it to S3. It worked perfectly on his machine. Then we hit production. Within an hour, users were reporting that their exports contained data from other customers. Because the filename was hardcoded, two concurrent requests were writing to the exact same file, stomping all over each other. It was a classic race condition that could have been avoided entirely with the right tool.
Automatic Naming and Uniqueness
When you need a place to stash data temporarily—maybe to pass a file to an external system command or to buffer a large dataset that doesn't fit in RAM—you should almost never pick the filename yourself. Ruby's Tempfile library handles this by generating a unique filename that is guaranteed not to collide with other processes.
When you initialize a Tempfile, Ruby creates a file in the system's temporary directory (usually /tmp on Unix) with a randomized name. You don't have to worry about File.exists? checks or appending timestamps to your filenames.
require 'tempfile'
# Create a tempfile. You can provide a prefix for easier debugging in /tmp
temp = Tempfile.new(['user_report', '.csv'])
begin
temp.puts("User ID, Email")
temp.puts("1, dev@example.com")
temp.rewind # Important: move the pointer back to the start before reading
puts "Temporary file created at: #{temp.path}"
puts "Content: #{temp.read}"
ensure
temp.close
temp.unlink # Deletes the file from the filesystem
end
Managing the Lifecycle and Cleanup
One of the best things about Tempfile is that it attempts to clean up after itself. If you forget to call unlink, Ruby will eventually delete the file when the object is garbage collected. However, I strongly advise against relying on the garbage collector. In a high-traffic production app, relying on the GC can lead to your /tmp directory filling up faster than the GC can keep up, which can crash your entire server.
The safest pattern is to use a begin...ensure block. By calling unlink in the ensure block, you guarantee the file is deleted even if an exception is raised during processing. I've seen too many "disk space exhausted" alerts caused by developers who assumed the GC would handle their temporary files.
Handling Binary Data and System Calls
Often, we use Tempfile because we need to pass a file path to a shell command or a third-party library that doesn't accept strings. If you're dealing with images, PDFs, or encrypted blobs, remember to set the file to binary mode. By default, Tempfile opens in text mode, which can mangle your data on some operating systems.
require 'tempfile'
# Use binmode for non-text data
temp = Tempfile.new('image_buffer', '.jpg')
temp.binmode
begin
# Imagine 'image_data' is a binary string from an API
image_data = "\xFF\xD8\xFF\xE0\x00\x10JFIF"
temp.write(image_data)
temp.flush # Ensure data is written to disk before the system call
# Pass the path to an external tool (e.g., ImageMagick)
system("identify #{temp.path}")
ensure
temp.close
temp.unlink
end
A quick tip: always call flush or close before passing the path to an external process. Otherwise, the external tool might try to read the file while the data is still sitting in Ruby's internal write buffer, resulting in a truncated or empty file.
📋 Practical Task
Building a Temporary Log Analysis Buffer
You need to create a script that simulates processing a large stream of log entries. Because the logs are too large to keep in a single array in memory, you will use a Tempfile to buffer them.
Write a script that does the following:
- Creates a
Tempfilewith the prefix'log_buffer'. - Iterates through an array of strings (simulate logs) and writes each one to the tempfile. Include at least five strings, some containing the word
"ERROR"and some containing"INFO". - Rewinds the file and reads it back line-by-line to count how many lines contain the word
"ERROR". - Prints the total error count and the path of the temporary file used.
- Ensures the file is closed and unlinked regardless of whether the process succeeds or fails.
There are no comments for now.