ruby
36 lines · 7 steps
How Rails jobs handle reverse geocoding
A background job turns signup coordinates into a readable address, with retries, guards, and safe database writes.
Explained by
highlit
1class ReverseGeocodeSignupJob < ApplicationJob
2 queue_as :default
3
4 retry_on Geocoder::OverQueryLimitError, wait: 5.minutes, attempts: 3
5 discard_on ActiveJob::DeserializationError
6
7 def perform(signup)
8 return if signup.latitude.blank? || signup.longitude.blank?
9
10 results = Geocoder.search([signup.latitude, signup.longitude])
11 result = results.first
12 return if result.nil?
13
14 signup.update_columns(
15 city: result.city,
16 region: result.state,
17 country_code: result.country_code&.upcase,
18 formatted_address: result.address,
19 geocoded_at: Time.current
20 )
21 end
22end
23
24class Signup < ApplicationRecord
25 validates :email, presence: true, uniqueness: { case_sensitive: false }
26
27 after_create_commit :enqueue_reverse_geocode
28
29 private
30
31 def enqueue_reverse_geocode
32 return unless latitude? && longitude?
33
34 ReverseGeocodeSignupJob.perform_later(self)
35 end
36end
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Offload slow, failure-prone external API calls to background jobs so the request cycle stays fast.
- 2Declarative retry_on and discard_on keep transient failures recoverable while dropping permanently invalid work.
- 3Guard clauses and update_columns let a job write results defensively without re-triggering callbacks.
Related explainers
rust
use serde::Deserialize; #[derive(Debug, Deserialize)] #[serde(untagged)]
Parsing flexible JSON shapes with serde
deserialization
enums
json
Intermediate
6 steps
ruby
require "shellwords" require "open3" module Backup
Building safe shell commands in Ruby
shell-out
subprocess
command-injection
Intermediate
7 steps
ruby
class UserAgentParser BROWSERS = [ [/Edg\/([\d.]+)/, "Edge"], [/OPR\/([\d.]+)/, "Opera"],
Parsing user-agent strings in Ruby
regex
pattern-matching
lookup-tables
Intermediate
8 steps
ruby
class LogAggregator BUCKET_FORMAT = "%Y-%m-%dT%H:%M" def initialize(entries)
Bucketing log entries by the minute in Ruby
aggregation
hashing
enumerable
Intermediate
5 steps
ruby
class WeeklySignupsReport DEFAULT_WEEKS = 12 def initialize(weeks: DEFAULT_WEEKS, source: User.all)
Building a weekly signups report in Rails
service object
aggregation
group by
Intermediate
7 steps
rust
use chrono::{Duration, NaiveDate}; #[derive(Debug)] pub struct DateRange {
Parsing and iterating date ranges in Rust
error-handling
iterators
parsing
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/how-rails-jobs-handle-reverse-geocoding-explained-ruby-a762/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.