234

I have been googling for about 90 minutes now and still don't have an answer to this. Where do I set default_url_options? I've already set it for config.action_mailer.default_url_options to solve this same bug elsewhere, but now I'm getting this error when trying to use a URL helper inside an RSpec spec. I have no idea where it's expecting default_url_options to be set.

 Failure/Error: listing_url(listing).should match(/\/\d+-\w+$/)
 RuntimeError:
   Missing host to link to! Please provide :host parameter or set default_url_options[:host]
 # ./spec/routing/listing_routing_spec.rb:9:in `block (3 levels) in <top (required)>'

This code has nothing to do with emails/ActionMailer, it just happens to need a URL instead of a path.

Any ideas?

Promise Preston
  • 24,334
  • 12
  • 145
  • 143
d11wtq
  • 34,788
  • 19
  • 120
  • 195

17 Answers17

301

You need to add the following line at every environment:

config.action_mailer.default_url_options = { :host => "yourhost" }

That way, it can work in all environments and could be different from environment to environment. For example:

development.rb

config.action_mailer.default_url_options = { :host => "dev.yourhost.com" }

test.rb

config.action_mailer.default_url_options = { :host => "test.yourhost.com" }

production.rb

config.action_mailer.default_url_options = { :host => "www.yourhost.com" }
p.matsinopoulos
  • 7,655
  • 6
  • 44
  • 92
Carlos Castillo
  • 3,218
  • 2
  • 14
  • 10
  • 22
    Also make sure that you restart your rails server after you add this. The files under config/ are not automatically reloaded. – Stenerson Sep 14 '13 at 20:09
  • 3
    I have done very similar to this and setting the default_url_option for action_mailer won't help. The use case is similar to this: Rails.application.routes.url_helpers.message_image_url(2) – Boti Jul 08 '14 at 08:50
  • 2
    Did this; with or without www... prefixing the host name in production, I still got the same error. Added the route per @d11wtq, and it worked. Is there some Rails4 change that caused this behavior? I never saw it before the upgrade, and only in one particular mail-send (devise-automated), since. – JosephK Oct 08 '14 at 12:23
  • Can confirm that this does not work in my Rails 4 projects. Setting it in routes is simply no option. – b1nary May 31 '16 at 12:10
  • Why does this error happen anyway? What is host: in the solution? What does that do? – Jwan622 Sep 08 '16 at 03:54
  • 4
    Not working in Rails 5. Added `default_url_options Rails.application.config.action_mailer.default_url_options` though and that did the trick, as suggested by another commenter – BooBailey Sep 03 '17 at 21:41
88
Your::Application.routes.draw do
  default_url_options :host => "example.com"

  # ... snip ...
end

Somewhere in routes.rb :)

ndnenkov
  • 35,425
  • 9
  • 72
  • 104
d11wtq
  • 34,788
  • 19
  • 120
  • 195
  • 41
    Not very good if you've got many different environments with differing URLs – Neil Middleton Dec 22 '11 at 15:22
  • 3
    Yeah what do you do if you have multiple env domains? – wejrowski Mar 02 '12 at 18:52
  • 1
    Presumably you just specify it for each URL instead, either in the route map, or in the url helper invocation: `listing_url(listing, :host => "whatever.com")`. – d11wtq Mar 03 '12 at 00:45
  • 16
    In the config file for each respective environment, I add this custom option: `config.domain = 'staging.myapp.com'` (of course substitute in a correct domain name for each env). Then in `routes.rb` I'm free to use `default_url_options host: Rails.application.config.domain` and it will work in any environment. You're welcome. – Prathan Thananart Aug 16 '12 at 00:29
  • 11
    A better approach would be to, within the routes file, do this: `default_url_options Rails.application.config.action_mailer.default_url_options`. – siannopollo Mar 28 '14 at 21:48
47

The host should be specified in each environment's config file. Eg:

config/environments/development.rb

See this question and this question.

ndnenkov
  • 35,425
  • 9
  • 72
  • 104
nickh
  • 4,721
  • 2
  • 29
  • 31
46

Set default_url_options to use your action_mailer.default_url_options.

In each of your environment files (e.g. development.rb, production.rb, etc.) you can specify the default_url_options to use for action_mailer:

config.action_mailer.default_url_options = { host: 'lvh.me', port: '3000' }

However, these are not set for MyApp:Application.default_url_options:

$ MyApp::Application.config.action_mailer.default_url_options
#=> {:host=>"lvh.me", :port=>"3000"}

$ MyApp::Application.default_url_options
#=> {}

That's why you are getting that error in anything outside of ActionMailer.

You can set your Application's default_url_options to use what you defined for action_mailer in the appropriate environment file (development.rb, production.rb, etc.).

To keep things as DRY as possible, do this in your config/environment.rb file so you only have to do this once:

# Initialize the rails application
MyApp::Application.initialize!

# Set the default host and port to be the same as Action Mailer.
MyApp::Application.default_url_options = MyApp::Application.config.action_mailer.default_url_options

Now when you boot up your app, your entire Application's default_url_options will match your action_mailer.default_url_options:

$ MyApp::Application.config.action_mailer.default_url_options
#=> {:host=>"lvh.me", :port=>"3000"}

$ MyApp::Application.default_url_options
#=> {:host=>"lvh.me", :port=>"3000"}

Hat tip to @pduersteler for leading me down this path.

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
  • 2
    Setting up the `config/environment.rb` as you described was the key for getting my mailer to work in the console. Thank you! – Eric D. Fields Mar 29 '18 at 21:17
  • @EricD.Fields You're very welcome, Eric! I find this so useful that I think it should be built into the Rails core. – Joshua Pinter Mar 29 '18 at 23:18
  • 4
    That would be `Rails.application.default_url_options = Rails.application.config.action_mailer.default_url_options` for Rails 5.2+ – Sandro L Aug 27 '19 at 10:25
  • Thanks, @SandroL! We're still on Rails 4.2 so haven't tested yet on later versions. – Joshua Pinter Sep 06 '19 at 01:50
  • 1
    A few people recommending this. I guess it's just that people tend to have action_mailer.default_url_options already configured for historical reasons, but isn't it more logical to set _that_ based on application.default_url_options rather than the other way around? Why involve a bogus mailer reference when configuring how your website links work? – Harry Wood Jun 02 '20 at 01:53
  • @HarryWood I would agree, but for those of us that have been around since Rails 2, it began with `action_mailer` and so that's where our typical host and port configuration is stored. – Joshua Pinter Jun 02 '20 at 20:54
25

When you use any listing_url method the full URL will be returned(not a relative one as normal). That's why rails is asking you for the host, to compute the whole URL.

How you can tell rails the host? You can do it in several ways:

1.Adding this option to each environment:

[/config/development.rb]
config.action_mailer.default_url_options = { host: "localhost:3000" }
[/config/test.rb]
config.action_mailer.default_url_options = { host: "localhost:3000" }
[/config/production.rb]
config.action_mailer.default_url_options = { host: "www.example.com" }

NOTE: If you are working inside a rails engine remember to do the same for your dummy app inside the engine tests: path_to_your_engine/test/dummy/config/environments/* because when you test the engine it's what rails is testing against.

2.Add the host option to the foo_url method like this:

listing_url(listing, host: request.host) # => 'http://localhost:3000/listings/1'

3.Not output the host with the option :only_path to true.

listing_url(listing, only_path: true ) # => '/listings/1'   

IMHO I don't see the point on this one because in this case I would use the listing_path method

ivanxuu
  • 842
  • 9
  • 10
  • Step 1 always works for me and today, using the refinery-cms gem just step 2 save me. Thanks for the comment. – lucianosousa Sep 29 '15 at 21:53
  • Very useful answer because of mentioning the scenario when you are working with a rails engine! In my case I ran into the error when trying to execute a rake task that was using a model inside an engine. I loaded my action_mailer config into the engine like this and was finally able to run the task. `MyEngine::Engine.config.action_mailer.default_url_options = Rails.application.config.action_mailer.default_url_options` `MyEngine::Engine.routes.default_url_options = Rails.application.config.action_mailer.default_url_options` – siax May 24 '22 at 09:17
19

Rails.application.routes.default_url_options[:host]= 'localhost:3000'

In the developemnt.rb / test.rb, can be more concise as following:

Rails.application.configure do
  # ... other config ...

  routes.default_url_options[:host] = 'localhost:3000'
end
Derek Fan
  • 817
  • 11
  • 10
16

Funny thing, that setting config.action_mailer.default_url_options does not help for me. Also, messing around with environment-independent settings in places I felt like it does not belong was not satisfying for me. Additionally, I wanted a solution that worked when generating urls in sidekiq/resque workers.

My approach so far, which goes into config/environments/{development, production}.rb:

MyApp::Application.configure do
    # Stuff omitted...

    config.action_mailer.default_url_options = {
      # Set things here as usual
    }
end

MyApp::Application.default_url_options = MyApp::Application.config.action_mailer.default_url_options

This works for me in rails >= 3.2.x.

pdu
  • 10,295
  • 4
  • 58
  • 95
  • 1
    This and only this worked for getting the mailer to include the URL, but it breaks other link_to functions in my app. –  Jul 14 '14 at 23:13
  • 1
    Great thinking, @pduesteler! I actually took this one step further and was able to add just one line in the `config/environment.rb` file to do this. And added answer that goes into detail: https://stackoverflow.com/a/48529627/293280 Thanks for pointing me in this direction. – Joshua Pinter Jan 30 '18 at 20:04
8

You can always pass host as a parameter to the URL helper:

listing_url(listing, host: request.host)
Undistraction
  • 42,754
  • 56
  • 195
  • 331
7

The above answer did not work for me, at least not as I wanted. I realised config.action_mailer.default_url_options = { host: "localhost", port: 3000 } after installing devise. Hope it will help someone with the same problem.

Ahmed J.
  • 484
  • 6
  • 11
6

go to config/environments/test.rb

Rails.application.routes.default_url_options[:host] = 'localhost:3000'

milad rahmani
  • 101
  • 1
  • 2
4

just in case someone finds this searching for errors concerning ActiveStorage:

if you have a controller-action where you want to generate upload-urls etc with the local disc-service (most likely in test environment), you need to include ActiveStorage::SetCurrent in the controller in order to allow blob.service_url_for_direct_upload to work correctly.

phoet
  • 18,688
  • 4
  • 46
  • 74
  • 1
    Thank you! Using this outside of a controller (GraphQL direct upload mutation) so had to tweak it a bit, but works. I've been looking for this, thanks again @phoet :) – Stan Jun 04 '20 at 16:40
3

You can set default url options in the Application Controller:

class ApplicationController < ActionController::Base
  def default_url_options
    {:locale => I18n.locale}
  end
end

http://guides.rubyonrails.org/action_controller_overview.html#default_url_options

RicRoberts
  • 39
  • 2
  • This is a good solution for Rails 4, because it lets you set options specific to a controller if necessary. – Ibrahim Feb 18 '16 at 20:31
2

I had this same error. I had everything written in correctly, including the Listing 10.13 from the tutorial.

Rails.application.configure do
.
.
.
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delevery_method :test
host = 'example.com'
config.action_mailer.default_url_options = { host: host }
.
.
.
end

obviously with "example.com" replaced with my server url.

What I had glossed over in the tutorial was this line:

After restarting the development server to activate the configuration...

So the answer for me was to turn the server off and back on again.

Okomikeruko
  • 1,123
  • 10
  • 22
0

Adding the default_url in routes not the right solution although, it works for some cases.

You've to set the default_url in each environment(development, test, production).

You need make these changes.

    config/environments/development.rb
     config.action_mailer.default_url_options = 
      { :host => 'your-host-name' }  #if it is local then 'localhost:3000'

 config/environments/test.rb
      config.action_mailer.default_url_options = 
      { :host => 'your-host-name' }  #if it is local then 'localhost:3000'

  config/environments/development.rb
     config.action_mailer.default_url_options = 
      { :host => 'your-host-name' }  #if it is local then 'localhost:3000'
Prabhakar
  • 6,458
  • 2
  • 40
  • 51
0

I solved the issue by configuring environment.rb as

YourApp::Application.default_url_options = YourApp::Application.config.action_mailer.default_url_options

You need to set default_url_options for action mailer against each environment like development, testing, staging and production etc.

Reference: Missing host to link to! Please provide :host parameter or set default_url_options[:host]

zeeshan
  • 11
  • 2
0

Didn't want to change the behavior for other environments, so I used:

development.rb

Rails.application.configure do
...
end

Rails.application.default_url_options = Rails.application.config.action_mailer.default_url_options

Works in Rails 6.

B Seven
  • 44,484
  • 66
  • 240
  • 385
0

Rails.application.config.action_mailer.default_url_options

config.action_mailer.default_url_options = { host: 'my.domain', protocol: 'https', port: 356 }

Rails.application.default_url_options

self.default_url_options = config.action_mailer.default_url_options

Firstly setup Action Mailer default url options (like in the most of the answers)

And after that assign that options to Application. Initial question is exactly about this config! Not about the mailer:) It is strange that question is old but not all answers setup this config and didn't mention simple self assignment

Put such lines into config/application.rb or into specific environment, for example into config/environments/development.rb

After that you can access to routes helpers like this

Rails.application.routes.url_helpers.user_url(25)
# => "https://my.domain:356/users/25"
mechnicov
  • 12,025
  • 4
  • 33
  • 56