---
title: "Default URL Options in Ruby on Rails"
description: "Understand default_url_options in Ruby on Rails and know where and how to use it. Tackle confusing things."
url: "https://qameta.com/posts/default-url-options-in-ruby-on-rails/"
image: "https://qameta.com/posts/default-url-options-in-ruby-on-rails/ruby-on-rails-default-url-options.png"
---

# Default URL Options in Ruby on Rails

![Ruby on Rails default_url_options in console](https://qameta.com/posts/default-url-options-in-ruby-on-rails/ruby-on-rails-default-url-options.png)

Like most [Ruby](https://www.ruby-lang.org) developers you have to set a
`default_url_options` on a [Ruby on Rails](https://rubyonrails.org) project.
Depending on the use case you have to set several of them with different values.

The name of the method `default_url_options` is the same, but it is used in
different contexts
([controller](https://guides.rubyonrails.org/action_controller_overview.html),
[mail](https://guides.rubyonrails.org/action_mailer_basics.html), or [file
storage](https://guides.rubyonrails.org/active_storage_overview.html), it may be
confusing and can even have side effects for your project you have to figure out
yourself. Depending on the value you set, they may be reused in other contexts
like
[ActiveStorage](https://guides.rubyonrails.org/active_storage_overview.html),
[ActionMailer](https://guides.rubyonrails.org/action_mailer_basics.html), and
third-party gems like [devise](https://rubygems.org/gems/devise). I couldn't
find any official documentation for the most common cases (web, mail, file
storage, test), I've written one.

## Building URLs in Ruby on Rails

First of all, let's figure out, what this setting is used for and dependent on
the setup in which contexts it is optional and where it is mandatory to be set
or to overwrite.

Start the [rails console in
development](https://guides.rubyonrails.org/getting_started.html#starting-up-the-web-server)
`RAILS_ENV=development` and check the values. This is for a newly created Ruby
on Rails 7 project:

```sh
# open the ruby on rails console (or bundle exec rails console)
bin/rails console
Loading development environment (Rails 7.0.7.2)
# check default URL (if not overwritten)
irb> app.url_options
=> {:host=>"www.example.com", :protocol=>"http"}
# build the root URL for the application
irb> app.root_url
=> "http://www.example.com/"
# check the global application setting
irb> Rails.application.default_url_options
=> {}
irb> Rails.application.routes.default_url_options
=> {}
```

We can see in the [rails
console](https://guides.rubyonrails.org/getting_started.html#using-a-model-to-interact-with-the-database)
and read in the documentation, the default value for the host is
`www.example.com` and for the protocol it is `http`. These values are
configured, they must be set, before the application will be instantiated:

```sh
bin/rails console
Loading development environment (Rails 7.0.7.2)
# check preset values
irb> app.root_url
=> "http://www.example.com/"
irb> Rails.application.routes.default_url_options = { host: "localhost", protocol: "http" }
# if you check now, you will find the old values
irb> app.url_options
=> {:host=>"www.example.com", :protocol=>"http"}
irb> app.root_url
=> "http://www.example.com/"
# create a new instance of app object with previously defined url options
irb> app(create = true)
app(create=true)
=>
#<ActionDispatch::Integration::Session:0x00000001078faab8
 @_mock_session=nil,
 @_routes=nil,
 @accept="text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
 @app=#<Ikos::Application>,
 @controller=nil,
 @host="localhost",
 @https=false,
 @named_routes_configured=true,
 @remote_addr="127.0.0.1",
 @request=nil,
 @request_count=0,
 @response=nil,
 @url_options=nil>
# check the new qpp url_options value
irb> app.url_options
=> {:host=>"localhost", :protocol=>"http"}
# generate a root_url
irb> app.root_url
=> "http://localhost/"
```

**Additional:** See all available objects and methods in the ruby on rails console
[Rails::ConsoleMethods](https://api.rubyonrails.org/classes/Rails/ConsoleMethods.html).

### Requests and URLs

If you request an URL through a browser, the URL is part of the request and is
provided within the request object:

```sh
# open the Ruby on Rails Console
$ bin/rails c
Loading development environment (Rails 7.0.7.2)
# Make a GET request to the application
irb> app.get "http://localhost:3000"
Started GET "/" for 127.0.0.1 at 2023-09-01 10:39:45 +0200
Processing by HomeController#index as HTML
  Rendering layout layouts/application.html.slim
  Rendering home/index.html.slim within layouts/application
  Rendered home/index.html.slim within layouts/application (Duration: 0.5ms | Allocations: 270)
  Rendered layout layouts/application.html.slim (Duration: 5.6ms | Allocations: 4361)
Completed 200 OK in 7ms (Views: 6.1ms | ActiveRecord: 0.0ms | Allocations: 4903)
# get the request object
irb> request = app.request
=> #<ActionDispatch::Request GET "http://localhost:3000/" for 127.0.0.1>
# read the URL from request
irb> request.url
=> "http://localhost:3000/"
```

The URL is part of a web request and is provided through HTTP protocol.

## ActionMailer and URLs

[ActionMailer](https://guides.rubyonrails.org/action_mailer_basics.html) doesn't
have a request. It don't know which URL it has to use in the emails. You have to
set it dependent on your use case.

### ActionMail setup for devise gem

Almost all Ruby on Rails developers used the [devise
gem](https://rubygems.org/gems/devise) at some point and have run the setup,
where you need a `default_url_options` for different environments (development,
test, production, and maybe staging):

```ruby
# config/environments/development.rb
config.action_mailer.default_url_options = {
  host: "localhost", port: 3000
}
# config/environments/test.rb
config.action_mailer.default_url_options = {
  host: "www.example.com", protocol: "http"
}
# config/environments/production.rb
config.action_mailer.default_url_options = {
  host: "www.production-site.com", protocol: "https"
}
```

Setting this parameter allows devise through ActionMailer to build URLs for a
password reset, password confirmation, and all the other emails. This setup is
ActionMailer related. It is valid for sending mails and most (if not all)
email-related third-party gems.

### ActionMailer and Rails Assets

If you want to use rails assets like images (logo, etc. located in
`app/assets/images`) in emails, you have to define, which asset URL should be
used. ActionMailer can be the same URL or another server, where the assets are
hosted:

```ruby
# define for every environment
# example in config/environments/production.rb
  config.action_mailer.asset_host = "https://www.production-site.com"
```

If you don't define an asset host, the files linked will be without an URL and
can't be loaded in emails.

**HINT:** Assets can also be delivered from a third-party service or a CDN
network. Check where your assets are located.

### ActionMailer and ActiveStorage URLs in mails

If you want to use
[ActiveStorage](https://guides.rubyonrails.org/active_storage_overview.html) for
delivering images, files, etc. in emails, you have to define default URL options
for Rails routes:

```sh
# config/environments/production.rb
Rails.application.routes.default_url_options = {
  host: "www.production-site.com",
  protocol: "https"
}
```

Check the
[ActiveStorage](https://guides.rubyonrails.org/active_storage_overview.html)
description below for more details.

## ActiveStorage and URLs

By default, Ruby on Rails delivers any
[ActiveStorage](https://guides.rubyonrails.org/active_storage_overview.html)
files through a controller, which verifies, that the user can access the
corresponding attachment. According to [DiskService#url_helpers
method](https://github.com/ceritium/rails/blob/main/activestorage/lib/active_storage/service/disk_service.rb#L168)
ActiveStorage is using `Rails.application.routes.url_helpers` by default:

```ruby
def url_helpers
  @url_helpers ||= Rails.application.routes.url_helpers
end
```

To set a default URL for ActiveStorage, you have to set it in routes
`default_url_options`:

```sh
# config/environments/production.rb
Rails.application.routes.default_url_options = { host: "www.production-site.com",
                                                 protocol: "https" }
```

Previously I've written a post regarding [Define Default URL for ActiveStorage
to fix Mixed Content
Error](https://qameta.com/posts/define-default-url-for-active-storage-to-fix-mixed-content-error/)
which has some more details around ActiveStorage and URLs.

## Rails testing environment and default URL options

By default the Ruby on Rails test environment uses these settings for URL:

```sh
$ RAILS_ENV="test" bin/rails console
Loading test environment (Rails 7.0.7.2)
irb> app.url_options
=> {:host=>"www.example.com", :protocol=>"http"}
```

Don't change the values for the test environment or it may break your browser
tests (in Rails called system tests). If you don't combine the problem with this
specific change, it will cost you a lot of time, to find the reason for the
problem.

## Third-party Gems and URLs

Dependent on the gem you have to check, which URL generator method or
configuration the gem is using. I've checked
the [devise gem](https://rubygems.org/gems/devise) and [noticed
gem](https://github.com/excid3/noticed). They both use the
`default_url_options` from routes:

```ruby
Rails.application.routes.default_url_options
```

Check the documentation and maybe the code, if it is missing in documentation.

## Things can get confusing

You have seen, there are several places, where you can and sometimes should
set up `default_url_options`. If you don't set any of the values, you will have
errors like:

```sh
$ bin/rails console
irb> Rails.application.default_url_options
=> {}
irb> Rails.application.routes.default_url_options
=> {}
# query the URL for the first user
irb> Rails.application.routes.url_helpers.url_for(User.first)
  ruby/3.2.2/lib/ruby/gems/3.2.0/gems/actionpack-7.0.7.2/lib/action_dispatch/http/url.rb:64:in `full_url_for': Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true (ArgumentError)

            raise ArgumentError, "Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true"
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

```

Now we set the missing value and check it again:

```sh
$ bin/rails console
irb> Rails.application.default_url_options = { host: "localhost", protocol: "http" }
# Get the URL for the first user
irb> Rails.application.routes.url_helpers.url_for(User.first)
=> "http://localhost/users/1"
```

But some of them are reused if set like:

```sh
bin/rails console
# check default values for application
irb> Rails.application.default_url_options
=> {}
# check default values for routes
irb> Rails.application.routes.default_url_options
=> {}
# check the value for application
irb> Rails.application.default_url_options = { host: "localhost", protocol: "http" }
# check routes value
Rails.application.routes.default_url_options
=> {:host=>"localhost", :protocol=>"http"}
```

If you set the value for routes, it is accessible in application configuration
too:

```sh
bin/rails console
# check default values for application
irb> Rails.application.default_url_options
=> {}
# check default values for routes
irb> Rails.application.routes.default_url_options
=> {}
# check the value for application
irb> Rails.application.routes.default_url_options = { host: "localhost", protocol: "http" }
# check routes value
Rails.application.default_url_options
=> {:host=>"localhost", :protocol=>"http"}
```

As recommended in most newer tutorial, host, protocol and port should be set in
routes configuration:

```ruby
Rails.application.routes.default_url_options = { host: "localhost", protocol: "http" }
```

### Routes changes affecting mailer and controller

If you set the value in routes, it is used in ActionMailer, ActiveStorage,
and ActionController too. You don't need to set it for each of them.

## Summary

If you hit problems with URLs in Ruby on Rails, it is really hard to figure out,
why and when something is wrong, missing, or has to be set. I've hit this in
several projects in different constellations, couldn't find a detailed
explanation, so it was time to write one.

For further reading check this post I've written before targeting this whole
topic in this post: [Define Default URL for ActiveStorage to fix Mixed Content
Error](https://qameta.com/posts/define-default-url-for-active-storage-to-fix-mixed-content-error/)
