JT Book a call

Blog

How to get & build full URLs in Rails

Published

3 min read

How to get & build full URLs in Rails

There are some cases when you want to get a current request absolute URL. Thankfully, Rails got you covered on this one and provides a simple way for that:

request.original_url

This’ll return an absolute full URL including schema, host, port, path, and query string, but without anchor though. The anchor (#section) never reaches your server: the browser keeps it to itself, so Rails has no way to know it.

So, for a request to https://example.com/resource?q=first:

request.original_url # => https://example.com/resource?q=first
request.fullpath # => /resource?q=first
request.path # => /resource

If you only need the scheme and host, for example to build a link back to your own site, use request.base_url. For the request above it returns https://example.com. A non-default port is kept, so a request to http://example.com:3000/resource?q=first gives an original_url of http://example.com:3000/resource?q=first.

Building full URL #

When you need to build a full URL in controller views you can simply use the URL helpers provided by Rails:

post_url(@post)

But it’s not that easy outside the request(controller/view) scope. For example, if you need to build a full URL inside a background job, Rails can’t simply get the host for that from a request, since there’s no request.

To make it work we need two things #

First, include URL helpers.

class MyJob < ApplicationJob
  include Rails.application.routes.url_helpers
  
  def perform(user)
    user_url(user)
    ...
  end
end

And then, set url options in app configuration:

# config/environments/production.rb
Rails.application.routes.default_url_options[:host] =  "example.com"
# And for email views
Rails.application.config.action_mailer.default_url_options = { host: "example.com" }

Without the host, the first user_url call in a job fails with ArgumentError: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true. That error is your sign that this step is missing.

Mailers read their own setting, config.action_mailer.default_url_options, as shown in the Action Mailer guide. Older snippets online set config.action_mailer[:host] instead. On Rails 8.1 that line stops the app from booting with undefined method 'host=' for class ActionMailer::Base, so use the default_url_options form.

If you need to generate URLs for assets (for example images/icons in emails) you’ll need to set asset_host as well:

# Need only if host is other than the one 
# that handles requests
config.action_controller.asset_host = 'example.com'

# Required since mailer has no request context 
# to get host address from
config.action_mailer.asset_host = 'https://example.com'

The mailer value needs the protocol (https://). A mailer has no request to copy it from, and the Action Mailer guide asks for it explicitly.

On Rails 8.1, with the host configured, both a job and a mailer produce http://example.com/users/42. To get https links, add protocol: "https" to the same default_url_options hash.

Read next

Tell us what you need built

JetThoughts has been building software since 2008. Book a call, or write to sales@jetthoughts.com. You'll leave the call with a written one-page scope within 2 working days.

#01 Paul Keen
Paul KeenChief Technology Officer & Open Source Contributor

A 30-minute call; pick a time.